diff options
author | Pierre Moreau <dev@pmoreau.org> | 2018-04-13 17:38:55 +0200 |
---|---|---|
committer | Alexey Sotkin <alexey.sotkin@intel.com> | 2018-04-24 12:21:49 +0300 |
commit | d1c02b3954cfdeaca99c0b5d17ce55f02c94e792 (patch) | |
tree | 86ce820fb95b32701222cee65924f2cb1e72c67f | |
parent | 01dddd07c475bcbb24a11931c649384c904e82d8 (diff) |
Change all line endings to UNIX-style
The code was currently using a mix of DOS-style and UNIX-style; LLVM
itself uses UNIX-style.
Commands used:
* dos2unix `find include -iname "*"`
* dos2unix `find lib -iname "*"`
* dos2unix `find test -iname "*"`
* dos2unix `find tools -iname "*"`
66 files changed, 21735 insertions, 21735 deletions
diff --git a/include/SPIRV.h b/include/SPIRV.h index 605e042..3ce9a0d 100644 --- a/include/SPIRV.h +++ b/include/SPIRV.h @@ -1,161 +1,161 @@ -//===- SPIRV.h – Read and write SPIR-V binary -------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file SPIRV.h
-///
-/// This files declares functions and passes for translating between LLVM and
-/// SPIR-V.
-///
-///
-//===----------------------------------------------------------------------===//
-#ifndef LLVM_SUPPORT_SPIRV_H
-#define LLVM_SUPPORT_SPIRV_H
-
-#include <string>
-#include <iostream>
-
-namespace llvm {
-// Pass initialization functions need to be declared before inclusion of
-// PassSupport.h.
-class PassRegistry;
-void initializeLLVMToSPIRVPass(PassRegistry&);
-void initializeOCL20To12Pass(PassRegistry&);
-void initializeOCL20ToSPIRVPass(PassRegistry&);
-void initializeOCL21ToSPIRVPass(PassRegistry&);
-void initializeOCLTypeToSPIRVPass(PassRegistry&);
-void initializeSPIRVLowerBoolPass(PassRegistry&);
-void initializeSPIRVLowerConstExprPass(PassRegistry&);
-void initializeSPIRVLowerOCLBlocksPass(PassRegistry&);
-void initializeSPIRVLowerMemmovePass(PassRegistry&);
-void initializeSPIRVRegularizeLLVMPass(PassRegistry&);
-void initializeSPIRVToOCL20Pass(PassRegistry&);
-void initializeTransOCLMDPass(PassRegistry&);
-}
-
-#include "llvm/IR/Module.h"
-
-namespace SPIRV {
-class SPIRVModule;
-
-/// \brief Check if a string contains SPIR-V binary.
-bool IsSPIRVBinary(std::string &Img);
-
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
-/// \brief Convert SPIR-V between binary and internal textual formats.
-/// This function is not thread safe and should not be used in multi-thread
-/// applications unless guarded by a critical section.
-/// \returns true if succeeds.
-bool ConvertSPIRV(std::istream &IS, llvm::raw_ostream &OS,
- std::string &ErrMsg, bool FromText, bool ToText);
-
-/// \brief Convert SPIR-V between binary and internel text formats.
-/// This function is not thread safe and should not be used in multi-thread
-/// applications unless guarded by a critical section.
-bool ConvertSPIRV(std::string &Input, std::string &Out,
- std::string &ErrMsg, bool ToText);
-
-/// \brief Check if a string contains SPIR-V in internal text format.
-bool IsSPIRVText(std::string &Img);
-#endif
-
-} // End namespace SPIRV
-
-namespace llvm {
-
-/// \brief Translate LLVM module to SPIRV and write to ostream.
-/// \returns true if succeeds.
-bool WriteSPIRV(llvm::Module *M, llvm::raw_ostream &OS, std::string &ErrMsg);
-
-/// \brief Load SPIRV from istream and translate to LLVM module.
-/// \returns true if succeeds.
-bool ReadSPIRV(llvm::LLVMContext &C, std::istream &IS, llvm::Module *&M,
- std::string &ErrMsg);
-
-/// \brief Regularize LLVM module by removing entities not representable by
-/// SPIRV.
-bool RegularizeLLVMForSPIRV(llvm::Module *M, std::string &ErrMsg);
-
-/// \brief Mangle OpenCL builtin function function name.
-void MangleOpenCLBuiltin(const std::string &UnmangledName,
- ArrayRef<Type*> ArgTypes, std::string &MangledName);
-
-/// Create a pass for translating LLVM to SPIR-V.
-ModulePass *createLLVMToSPIRV(SPIRV::SPIRVModule *);
-
-/// Create a pass for translating OCL 2.0 builtin functions to equivalent
-/// OCL 1.2 builtin functions.
-ModulePass *createOCL20To12();
-
-/// Create a pass for translating OCL 2.0 builtin functions to SPIR-V builtin
-/// functions.
-ModulePass *createOCL20ToSPIRV();
-
-/// Create a pass for translating OCL 2.1 builtin functions to SPIR-V builtin
-/// functions.
-ModulePass *createOCL21ToSPIRV();
-
-/// Create a pass for adapting OCL types for SPIRV.
-ModulePass *createOCLTypeToSPIRV();
-
-/// Create a pass for lowering cast instructions of i1 type.
-ModulePass *createSPIRVLowerBool();
-
-/// Create a pass for lowering constant expressions to instructions.
-ModulePass *createSPIRVLowerConstExpr();
-
-/// Create a pass for lowering OCL 2.0 blocks to functions calls.
-ModulePass *createSPIRVLowerOCLBlocks();
-
-/// Create a pass for lowering llvm.memmove to llvm.memcpys with a temporary variable.
-ModulePass *createSPIRVLowerMemmove();
-
-/// Create a pass for regularize LLVM module to be translated to SPIR-V.
-ModulePass *createSPIRVRegularizeLLVM();
-
-/// Create a pass for translating SPIR-V builtin functions to OCL 2.0 builtin
-/// functions.
-ModulePass *createSPIRVToOCL20();
-
-/// Create a pass for translating SPIR 1.2/2.0 metadata to SPIR-V friendly
-/// metadata.
-ModulePass *createTransOCLMD();
-
-/// Create and return a pass that writes the module to the specified
-/// ostream.
-ModulePass *createSPIRVWriterPass(llvm::raw_ostream &Str);
-
-} // namespace llvm
-
-
-
-#endif
+//===- SPIRV.h – Read and write SPIR-V binary -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// 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. +// +//===----------------------------------------------------------------------===// +/// \file SPIRV.h +/// +/// This files declares functions and passes for translating between LLVM and +/// SPIR-V. +/// +/// +//===----------------------------------------------------------------------===// +#ifndef LLVM_SUPPORT_SPIRV_H +#define LLVM_SUPPORT_SPIRV_H + +#include <string> +#include <iostream> + +namespace llvm { +// Pass initialization functions need to be declared before inclusion of +// PassSupport.h. +class PassRegistry; +void initializeLLVMToSPIRVPass(PassRegistry&); +void initializeOCL20To12Pass(PassRegistry&); +void initializeOCL20ToSPIRVPass(PassRegistry&); +void initializeOCL21ToSPIRVPass(PassRegistry&); +void initializeOCLTypeToSPIRVPass(PassRegistry&); +void initializeSPIRVLowerBoolPass(PassRegistry&); +void initializeSPIRVLowerConstExprPass(PassRegistry&); +void initializeSPIRVLowerOCLBlocksPass(PassRegistry&); +void initializeSPIRVLowerMemmovePass(PassRegistry&); +void initializeSPIRVRegularizeLLVMPass(PassRegistry&); +void initializeSPIRVToOCL20Pass(PassRegistry&); +void initializeTransOCLMDPass(PassRegistry&); +} + +#include "llvm/IR/Module.h" + +namespace SPIRV { +class SPIRVModule; + +/// \brief Check if a string contains SPIR-V binary. +bool IsSPIRVBinary(std::string &Img); + +#ifdef _SPIRV_SUPPORT_TEXT_FMT +/// \brief Convert SPIR-V between binary and internal textual formats. +/// This function is not thread safe and should not be used in multi-thread +/// applications unless guarded by a critical section. +/// \returns true if succeeds. +bool ConvertSPIRV(std::istream &IS, llvm::raw_ostream &OS, + std::string &ErrMsg, bool FromText, bool ToText); + +/// \brief Convert SPIR-V between binary and internel text formats. +/// This function is not thread safe and should not be used in multi-thread +/// applications unless guarded by a critical section. +bool ConvertSPIRV(std::string &Input, std::string &Out, + std::string &ErrMsg, bool ToText); + +/// \brief Check if a string contains SPIR-V in internal text format. +bool IsSPIRVText(std::string &Img); +#endif + +} // End namespace SPIRV + +namespace llvm { + +/// \brief Translate LLVM module to SPIRV and write to ostream. +/// \returns true if succeeds. +bool WriteSPIRV(llvm::Module *M, llvm::raw_ostream &OS, std::string &ErrMsg); + +/// \brief Load SPIRV from istream and translate to LLVM module. +/// \returns true if succeeds. +bool ReadSPIRV(llvm::LLVMContext &C, std::istream &IS, llvm::Module *&M, + std::string &ErrMsg); + +/// \brief Regularize LLVM module by removing entities not representable by +/// SPIRV. +bool RegularizeLLVMForSPIRV(llvm::Module *M, std::string &ErrMsg); + +/// \brief Mangle OpenCL builtin function function name. +void MangleOpenCLBuiltin(const std::string &UnmangledName, + ArrayRef<Type*> ArgTypes, std::string &MangledName); + +/// Create a pass for translating LLVM to SPIR-V. +ModulePass *createLLVMToSPIRV(SPIRV::SPIRVModule *); + +/// Create a pass for translating OCL 2.0 builtin functions to equivalent +/// OCL 1.2 builtin functions. +ModulePass *createOCL20To12(); + +/// Create a pass for translating OCL 2.0 builtin functions to SPIR-V builtin +/// functions. +ModulePass *createOCL20ToSPIRV(); + +/// Create a pass for translating OCL 2.1 builtin functions to SPIR-V builtin +/// functions. +ModulePass *createOCL21ToSPIRV(); + +/// Create a pass for adapting OCL types for SPIRV. +ModulePass *createOCLTypeToSPIRV(); + +/// Create a pass for lowering cast instructions of i1 type. +ModulePass *createSPIRVLowerBool(); + +/// Create a pass for lowering constant expressions to instructions. +ModulePass *createSPIRVLowerConstExpr(); + +/// Create a pass for lowering OCL 2.0 blocks to functions calls. +ModulePass *createSPIRVLowerOCLBlocks(); + +/// Create a pass for lowering llvm.memmove to llvm.memcpys with a temporary variable. +ModulePass *createSPIRVLowerMemmove(); + +/// Create a pass for regularize LLVM module to be translated to SPIR-V. +ModulePass *createSPIRVRegularizeLLVM(); + +/// Create a pass for translating SPIR-V builtin functions to OCL 2.0 builtin +/// functions. +ModulePass *createSPIRVToOCL20(); + +/// Create a pass for translating SPIR 1.2/2.0 metadata to SPIR-V friendly +/// metadata. +ModulePass *createTransOCLMD(); + +/// Create and return a pass that writes the module to the specified +/// ostream. +ModulePass *createSPIRVWriterPass(llvm::raw_ostream &Str); + +} // namespace llvm + + + +#endif diff --git a/lib/SPIRV/CMakeLists.txt b/lib/SPIRV/CMakeLists.txt index b4203b0..6fcb6ed 100644 --- a/lib/SPIRV/CMakeLists.txt +++ b/lib/SPIRV/CMakeLists.txt @@ -1,52 +1,52 @@ -option(SPIRV_USE_LLVM_API "Enable usage of LLVM API for libSPIRV." ON)
-if(SPIRV_USE_LLVM_API)
- add_definitions(-D_SPIRV_LLVM_API)
-endif(SPIRV_USE_LLVM_API)
-
-add_llvm_library(LLVMSPIRVLib SHARED
- libSPIRV/SPIRVBasicBlock.cpp
- libSPIRV/SPIRVDebug.cpp
- libSPIRV/SPIRVDecorate.cpp
- libSPIRV/SPIRVEntry.cpp
- libSPIRV/SPIRVFunction.cpp
- libSPIRV/SPIRVInstruction.cpp
- libSPIRV/SPIRVModule.cpp
- libSPIRV/SPIRVStream.cpp
- libSPIRV/SPIRVType.cpp
- libSPIRV/SPIRVValue.cpp
- Mangler/FunctionDescriptor.cpp
- Mangler/Mangler.cpp
- Mangler/ManglingUtils.cpp
- Mangler/ParameterType.cpp
- OCL20To12.cpp
- OCL20ToSPIRV.cpp
- OCL21ToSPIRV.cpp
- OCLTypeToSPIRV.cpp
- OCLUtil.cpp
- SPIRVLowerBool.cpp
- SPIRVLowerConstExpr.cpp
- SPIRVLowerMemmove.cpp
- SPIRVLowerOCLBlocks.cpp
- SPIRVReader.cpp
- SPIRVRegularizeLLVM.cpp
- SPIRVToOCL20.cpp
- SPIRVUtil.cpp
- SPIRVWriter.cpp
- SPIRVWriterPass.cpp
- TransOCLMD.cpp
- LINK_COMPONENTS
- Analysis
- BitWriter
- Core
- Support
- TransformUtils
-)
-
-target_include_directories(LLVMSPIRVLib
- PRIVATE
- ${LLVM_INCLUDE_DIR}
- ${LLVM_SPIRV_INCLUDE_DIRS}
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_SOURCE_DIR}/libSPIRV
- ${CMAKE_CURRENT_SOURCE_DIR}/Mangler
-)
+option(SPIRV_USE_LLVM_API "Enable usage of LLVM API for libSPIRV." ON) +if(SPIRV_USE_LLVM_API) + add_definitions(-D_SPIRV_LLVM_API) +endif(SPIRV_USE_LLVM_API) + +add_llvm_library(LLVMSPIRVLib SHARED + libSPIRV/SPIRVBasicBlock.cpp + libSPIRV/SPIRVDebug.cpp + libSPIRV/SPIRVDecorate.cpp + libSPIRV/SPIRVEntry.cpp + libSPIRV/SPIRVFunction.cpp + libSPIRV/SPIRVInstruction.cpp + libSPIRV/SPIRVModule.cpp + libSPIRV/SPIRVStream.cpp + libSPIRV/SPIRVType.cpp + libSPIRV/SPIRVValue.cpp + Mangler/FunctionDescriptor.cpp + Mangler/Mangler.cpp + Mangler/ManglingUtils.cpp + Mangler/ParameterType.cpp + OCL20To12.cpp + OCL20ToSPIRV.cpp + OCL21ToSPIRV.cpp + OCLTypeToSPIRV.cpp + OCLUtil.cpp + SPIRVLowerBool.cpp + SPIRVLowerConstExpr.cpp + SPIRVLowerMemmove.cpp + SPIRVLowerOCLBlocks.cpp + SPIRVReader.cpp + SPIRVRegularizeLLVM.cpp + SPIRVToOCL20.cpp + SPIRVUtil.cpp + SPIRVWriter.cpp + SPIRVWriterPass.cpp + TransOCLMD.cpp + LINK_COMPONENTS + Analysis + BitWriter + Core + Support + TransformUtils +) + +target_include_directories(LLVMSPIRVLib + PRIVATE + ${LLVM_INCLUDE_DIR} + ${LLVM_SPIRV_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/libSPIRV + ${CMAKE_CURRENT_SOURCE_DIR}/Mangler +) diff --git a/lib/SPIRV/LLVMBuild.txt b/lib/SPIRV/LLVMBuild.txt index 18a6be6..539b617 100644 --- a/lib/SPIRV/LLVMBuild.txt +++ b/lib/SPIRV/LLVMBuild.txt @@ -1,23 +1,23 @@ -;===- ./lib/Target/SPIRV/Common/LLVMBuild.txt ------------------*- Conf -*--===;
-;
-; The LLVM Compiler Infrastructure
-;
-; This file is distributed under the University of Illinois Open Source
-; License. See LICENSE.TXT for details.
-;
-;===------------------------------------------------------------------------===;
-;
-; This is an LLVMBuild description file for the components in this subdirectory.
-;
-; For more information on the LLVMBuild system, please see:
-;
-; http://llvm.org/docs/LLVMBuild.html
-;
-;===------------------------------------------------------------------------===;
-
-[component_0]
-type = Library
-name = SPIRVLib
-parent = Libraries
-required_libraries = Core Support Analysis IPO
-
+;===- ./lib/Target/SPIRV/Common/LLVMBuild.txt ------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = SPIRVLib +parent = Libraries +required_libraries = Core Support Analysis IPO + diff --git a/lib/SPIRV/OCL20ToSPIRV.cpp b/lib/SPIRV/OCL20ToSPIRV.cpp index c3e3eb6..a3d93ee 100644 --- a/lib/SPIRV/OCL20ToSPIRV.cpp +++ b/lib/SPIRV/OCL20ToSPIRV.cpp @@ -1,1543 +1,1543 @@ -//===- OCL20ToSPIRV.cpp - Transform OCL20 to SPIR-V builtins -----*- 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 implements translation of OCL20 builtin functions.
-//
-//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "cl20tospv"
-
-#include "SPIRVInternal.h"
-#include "OCLUtil.h"
-#include "OCLTypeToSPIRV.h"
-
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/IR/InstVisitor.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/Instruction.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"
-
-#include <set>
-
-using namespace llvm;
-using namespace SPIRV;
-using namespace OCLUtil;
-
-namespace SPIRV {
-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 OCL20ToSPIRV: public ModulePass,
- public InstVisitor<OCL20ToSPIRV> {
-public:
- OCL20ToSPIRV():ModulePass(ID), M(nullptr), Ctx(nullptr), CLVer(0) {
- initializeOCL20ToSPIRVPass(*PassRegistry::getPassRegistry());
- }
- virtual bool runOnModule(Module &M);
-
- void getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<OCLTypeToSPIRV>();
- }
-
- virtual void visitCallInst(CallInst &CI);
-
- /// Transform barrier/work_group_barrier/sub_group_barrier
- /// to __spirv_ControlBarrier.
- /// barrier(flag) =>
- /// __spirv_ControlBarrier(workgroup, workgroup, map(flag))
- /// work_group_barrier(scope, flag) =>
- /// __spirv_ControlBarrier(workgroup, map(scope), map(flag))
- /// sub_group_barrier(scope, flag) =>
- /// __spirv_ControlBarrier(subgroup, map(scope), map(flag))
- void visitCallBarrier(CallInst *CI);
-
- /// Erase useless convert functions.
- /// \return true if the call instruction is erased.
- bool eraseUselessConvert(CallInst *Call, const std::string &MangledName,
- const std::string &DeMangledName);
-
- /// Transform convert_ to
- /// __spirv_{CastOpName}_R{TargeTyName}{_sat}{_rt[p|n|z|e]}
- void visitCallConvert(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName);
-
- /// Transform async_work_group{_strided}_copy.
- /// async_work_group_copy(dst, src, n, event)
- /// => async_work_group_strided_copy(dst, src, n, 1, event)
- /// async_work_group_strided_copy(dst, src, n, stride, event)
- /// => __spirv_AsyncGroupCopy(ScopeWorkGroup, dst, src, n, stride, event)
- void visitCallAsyncWorkGroupCopy(CallInst *CI,
- const std::string &DemangledName);
-
- /// Transform OCL builtin function to SPIR-V builtin function.
- void transBuiltin(CallInst *CI, OCLBuiltinTransInfo &Info);
-
- /// Transform OCL work item builtin functions to SPIR-V builtin variables.
- void transWorkItemBuiltinsToVariables();
-
- /// 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 all to __spirv_Op(All|Any). Note that the types mismatch so
- // some extra code is emitted to convert between the two.
- void visitCallAllAny(spv::Op OC, CallInst *CI);
-
- /// 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 atomic_compare_exchange call.
- /// In atomic_compare_exchange, the expected value parameter is a pointer.
- /// However in SPIR-V it is a value. The transformation adds a load
- /// instruction, result of which is passed to atomic_compare_exchange as
- /// argument.
- /// The transformation adds a store instruction after the call, to update the
- /// value in expected with the value pointed to by object. Though, it is not
- /// necessary in case they are equal, this approach makes result code simpler.
- /// Also ICmp instruction is added, because the call must return result of
- /// comparison.
- /// \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 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 OCL builtin function to SPIR-V builtin function.
- /// Assuming there is a simple name mapping without argument changes.
- /// Should be called at last.
- void visitCallBuiltinSimple(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName);
-
- /// Transform get_image_{width|height|depth|dim}.
- /// get_image_xxx(...) =>
- /// dimension = __spirv_ImageQuerySizeLod_R{ReturnType}(...);
- /// return dimension.{x|y|z};
- void visitCallGetImageSize(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName);
-
- /// Transform {work|sub}_group_x =>
- /// __spirv_{OpName}
- ///
- /// Special handling of work_group_broadcast.
- /// work_group_broadcast(a, x, y, z)
- /// =>
- /// __spirv_GroupBroadcast(a, vec3(x, y, z))
-
- void visitCallGroupBuiltin(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 OCL pipe builtin function to SPIR-V pipe builtin function.
- void visitCallPipeBuiltin(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName);
-
- /// Transform read_image with sampler arguments.
- /// read_image(image, sampler, ...) =>
- /// sampled_image = __spirv_SampledImage(image, sampler);
- /// return __spirv_ImageSampleExplicitLod_R{ReturnType}(sampled_image, ...);
- void visitCallReadImageWithSampler(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName);
-
- /// Transform read_image with msaa image arguments.
- /// Sample argument must be acoded as Image Operand.
- void visitCallReadImageMSAA(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName);
-
- /// Transform {read|write}_image without sampler arguments.
- void visitCallReadWriteImage(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName);
-
- /// Transform to_{global|local|private}.
- ///
- /// T* a = ...;
- /// addr T* b = to_addr(a);
- /// =>
- /// i8* x = cast<i8*>(a);
- /// addr i8* y = __spirv_GenericCastToPtr_ToAddr(x);
- /// addr T* b = cast<addr T*>(y);
- void visitCallToAddr(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName);
-
- /// Transform return type of relatinal built-in functions like isnan, isfinite
- /// to boolean values.
- void visitCallRelational(CallInst *CI, const std::string &DemangledName);
-
- /// Transform vector load/store functions to SPIR-V extended builtin
- /// functions
- /// {vload|vstore{a}}{_half}{n}{_rte|_rtz|_rtp|_rtn} =>
- /// __spirv_ocl_{ExtendedInstructionOpCodeName}__R{ReturnType}
- void visitCallVecLoadStore(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName);
-
- /// Transforms get_mem_fence built-in to SPIR-V function and aligns result values with SPIR 1.2.
- /// get_mem_fence(ptr) => __spirv_GenericPtrMemSemantics
- /// GenericPtrMemSemantics valid values are 0x100, 0x200 and 0x300, where is
- /// SPIR 1.2 defines them as 0x1, 0x2 and 0x3, so this function adjusts
- /// GenericPtrMemSemantics results to SPIR 1.2 values.
- void visitCallGetFence(CallInst *CI, StringRef MangledName, const std::string& DemangledName);
-
- /// Transforms OpDot instructions with a scalar type to a fmul instruction
- void visitCallDot(CallInst *CI);
-
- /// Fixes for built-in functions with vector+scalar arguments that are
- /// translated to the SPIR-V instructions where all arguments must have the
- /// same type.
- void visitCallScalToVec(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName);
-
- /// Transform get_image_channel_{order|data_type} built-in functions to
- /// __spirv_ocl_{ImageQueryOrder|ImageQueryFormat}
- void visitCallGetImageChannel(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName,
- unsigned int Offset);
-
- /// For cl_intel_subgroups block read built-ins:
- void visitSubgroupBlockReadINTEL(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName);
-
- /// For cl_intel_subgroups block write built-ins:
- void visitSubgroupBlockWriteINTEL(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName);
-
- void visitDbgInfoIntrinsic(DbgInfoIntrinsic &I){
- I.dropAllReferences();
- I.eraseFromParent();
- }
- static char ID;
-private:
- Module *M;
- LLVMContext *Ctx;
- unsigned CLVer; /// OpenCL version as major*10+minor
- std::set<Value *> ValuesToDelete;
-
- ConstantInt *addInt32(int I) {
- return getInt32(M, I);
- }
- ConstantInt *addSizet(uint64_t I) {
- return getSizet(M, I);
- }
-
- /// Get vector width from OpenCL vload* function name.
- SPIRVWord getVecLoadWidth(const std::string& DemangledName) {
- SPIRVWord Width = 0;
- if (DemangledName == "vloada_half")
- Width = 1;
- else {
- unsigned Loc = 5;
- if (DemangledName.find("vload_half") == 0)
- Loc = 10;
- else if (DemangledName.find("vloada_half") == 0)
- Loc = 11;
-
- std::stringstream SS(DemangledName.substr(Loc));
- SS >> Width;
- }
- return Width;
- }
-
- /// Transform OpenCL vload/vstore function name.
- void transVecLoadStoreName(std::string& DemangledName,
- const std::string &Stem, bool AlwaysN) {
- auto HalfStem = Stem + "_half";
- auto HalfStemR = HalfStem + "_r";
- if (!AlwaysN && DemangledName == HalfStem)
- return;
- if (!AlwaysN && DemangledName.find(HalfStemR) == 0) {
- DemangledName = HalfStemR;
- return;
- }
- if (DemangledName.find(HalfStem) == 0) {
- auto OldName = DemangledName;
- DemangledName = HalfStem + "n";
- if (OldName.find("_r") != std::string::npos)
- DemangledName += "_r";
- return;
- }
- if (DemangledName.find(Stem) == 0) {
- DemangledName = Stem + "n";
- return;
- }
- }
-
-};
-
-char OCL20ToSPIRV::ID = 0;
-
-bool
-OCL20ToSPIRV::runOnModule(Module& Module) {
- M = &Module;
- Ctx = &M->getContext();
- auto Src = getSPIRVSource(&Module);
- if (std::get<0>(Src) != spv::SourceLanguageOpenCL_C)
- return false;
-
- CLVer = std::get<1>(Src);
- if (CLVer > kOCLVer::CL20)
- return false;
-
- DEBUG(dbgs() << "Enter OCL20ToSPIRV:\n");
-
- transWorkItemBuiltinsToVariables();
-
- visit(*M);
-
- for (auto &I:ValuesToDelete)
- if (auto Inst = dyn_cast<Instruction>(I))
- Inst->eraseFromParent();
- for (auto &I:ValuesToDelete)
- if (auto GV = dyn_cast<GlobalValue>(I))
- GV->eraseFromParent();
-
- DEBUG(dbgs() << "After OCL20ToSPIRV:\n" << *M);
-
- std::string Err;
- raw_string_ostream ErrorOS(Err);
- if (verifyModule(*M, &ErrorOS)){
- DEBUG(errs() << "Fails to verify module: " << ErrorOS.str());
- }
- return true;
-}
-
-// The order of handling OCL builtin functions is important.
-// Workgroup functions need to be handled before pipe functions since
-// there are functions fall into both categories.
-void
-OCL20ToSPIRV::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, &DemangledName))
- return;
-
- DEBUG(dbgs() << "DemangledName: " << DemangledName << '\n');
- if (DemangledName.find(kOCLBuiltinName::NDRangePrefix) == 0) {
- visitCallNDRange(&CI, DemangledName);
- return;
- }
- if (DemangledName == kOCLBuiltinName::All) {
- visitCallAllAny(OpAll, &CI);
- return;
- }
- if (DemangledName == kOCLBuiltinName::Any) {
- visitCallAllAny(OpAny, &CI);
- return;
- }
- if (DemangledName.find(kOCLBuiltinName::AsyncWorkGroupCopy) == 0 ||
- DemangledName.find(kOCLBuiltinName::AsyncWorkGroupStridedCopy) == 0) {
- visitCallAsyncWorkGroupCopy(&CI, DemangledName);
- return;
- }
- 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::AtomicCmpXchgWeak ||
- DemangledName == kOCLBuiltinName::AtomicCmpXchgStrong ||
- DemangledName == kOCLBuiltinName::AtomicCmpXchgWeakExplicit ||
- DemangledName == kOCLBuiltinName::AtomicCmpXchgStrongExplicit) {
- assert(CLVer == kOCLVer::CL20 && "Wrong version of OpenCL");
- PCI = visitCallAtomicCmpXchg(PCI, DemangledName);
- }
- visitCallAtomicLegacy(PCI, MangledName, DemangledName);
- visitCallAtomicCpp11(PCI, MangledName, DemangledName);
- return;
- }
- if (DemangledName.find(kOCLBuiltinName::ConvertPrefix) == 0) {
- visitCallConvert(&CI, MangledName, DemangledName);
- return;
- }
- if (DemangledName == kOCLBuiltinName::GetImageWidth ||
- DemangledName == kOCLBuiltinName::GetImageHeight ||
- DemangledName == kOCLBuiltinName::GetImageDepth ||
- DemangledName == kOCLBuiltinName::GetImageDim ||
- DemangledName == kOCLBuiltinName::GetImageArraySize) {
- visitCallGetImageSize(&CI, MangledName, DemangledName);
- return;
- }
- if ((DemangledName.find(kOCLBuiltinName::WorkGroupPrefix) == 0 &&
- DemangledName != kOCLBuiltinName::WorkGroupBarrier) ||
- DemangledName == kOCLBuiltinName::WaitGroupEvent ||
- (DemangledName.find(kOCLBuiltinName::SubGroupPrefix) == 0 &&
- DemangledName != kOCLBuiltinName::SubGroupBarrier)) {
- visitCallGroupBuiltin(&CI, MangledName, DemangledName);
- return;
- }
- if (DemangledName.find(kOCLBuiltinName::Pipe) != std::string::npos) {
- visitCallPipeBuiltin(&CI, MangledName, DemangledName);
- return;
- }
- if (DemangledName == kOCLBuiltinName::MemFence) {
- visitCallMemFence(&CI);
- return;
- }
- if (DemangledName.find(kOCLBuiltinName::ReadImage) == 0) {
- if (MangledName.find(kMangledName::Sampler) != StringRef::npos) {
- visitCallReadImageWithSampler(&CI, MangledName, DemangledName);
- return;
- }
- if (MangledName.find("msaa") != StringRef::npos) {
- visitCallReadImageMSAA(&CI, MangledName, DemangledName);
- return;
- }
- }
- if (DemangledName.find(kOCLBuiltinName::ReadImage) == 0 ||
- DemangledName.find(kOCLBuiltinName::WriteImage) == 0) {
- visitCallReadWriteImage(&CI, MangledName, DemangledName);
- return;
- }
- if (DemangledName == kOCLBuiltinName::ToGlobal ||
- DemangledName == kOCLBuiltinName::ToLocal ||
- DemangledName == kOCLBuiltinName::ToPrivate) {
- visitCallToAddr(&CI, MangledName, DemangledName);
- return;
- }
- if (DemangledName.find(kOCLBuiltinName::VLoadPrefix) == 0 ||
- DemangledName.find(kOCLBuiltinName::VStorePrefix) == 0) {
- visitCallVecLoadStore(&CI, MangledName, DemangledName);
- return;
- }
- if (DemangledName == kOCLBuiltinName::IsFinite ||
- DemangledName == kOCLBuiltinName::IsInf ||
- DemangledName == kOCLBuiltinName::IsNan ||
- DemangledName == kOCLBuiltinName::IsNormal ||
- DemangledName == kOCLBuiltinName::Signbit) {
- visitCallRelational(&CI, DemangledName);
- return;
- }
- if (DemangledName == kOCLBuiltinName::WorkGroupBarrier ||
- DemangledName == kOCLBuiltinName::Barrier) {
- visitCallBarrier(&CI);
- return;
- }
- if (DemangledName == kOCLBuiltinName::GetFence) {
- visitCallGetFence(&CI, MangledName, DemangledName);
- return;
- }
- if (DemangledName == kOCLBuiltinName::Dot &&
- !(CI.getOperand(0)->getType()->isVectorTy())) {
- visitCallDot(&CI);
- return;
- }
- if (DemangledName == kOCLBuiltinName::FMin ||
- DemangledName == kOCLBuiltinName::FMax ||
- DemangledName == kOCLBuiltinName::Min ||
- DemangledName == kOCLBuiltinName::Max ||
- DemangledName == kOCLBuiltinName::Step ||
- DemangledName == kOCLBuiltinName::SmoothStep ||
- DemangledName == kOCLBuiltinName::Clamp ||
- DemangledName == kOCLBuiltinName::Mix) {
- visitCallScalToVec(&CI, MangledName, DemangledName);
- return;
- }
- if (DemangledName == kOCLBuiltinName::GetImageChannelDataType) {
- visitCallGetImageChannel(&CI, MangledName, DemangledName,
- OCLImageChannelDataTypeOffset);
- return;
- }
- if (DemangledName == kOCLBuiltinName::GetImageChannelOrder) {
- visitCallGetImageChannel(&CI, MangledName, DemangledName,
- OCLImageChannelOrderOffset);
- return;
- }
- if (DemangledName.find(kOCLBuiltinName::SubgroupBlockReadINTELPrefix) == 0) {
- visitSubgroupBlockReadINTEL(&CI, MangledName, DemangledName);
- return;
- }
- if (DemangledName.find(kOCLBuiltinName::SubgroupBlockWriteINTELPrefix) == 0) {
- visitSubgroupBlockWriteINTEL(&CI, MangledName, DemangledName);
- return;
- }
- visitCallBuiltinSimple(&CI, MangledName, DemangledName);
-}
-
-void
-OCL20ToSPIRV::visitCallNDRange(CallInst *CI,
- const std::string &DemangledName) {
- assert(DemangledName.find(kOCLBuiltinName::NDRangePrefix) == 0);
- std::string lenStr = DemangledName.substr(8, 1);
- auto Len = atoi(lenStr.c_str());
- assert (Len >= 1 && Len <= 3);
- // SPIR-V ndrange structure requires 3 members in the following order:
- // global work offset
- // global work size
- // local work size
- // The arguments need to add missing members.
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args){
- for (size_t I = 1, E = Args.size(); I != E; ++I)
- Args[I] = getScalarOrArray(Args[I], Len, CI);
- switch (Args.size()) {
- case 2: {
- // Has global work size.
- auto T = Args[1]->getType();
- auto C = getScalarOrArrayConstantInt(CI, T, Len, 0);
- Args.push_back(C);
- Args.push_back(C);
- }
- break;
- case 3: {
- // Has global and local work size.
- auto T = Args[1]->getType();
- Args.push_back(getScalarOrArrayConstantInt(CI, T, Len, 0));
- }
- break;
- case 4: {
- // Move offset arg to the end
- auto OffsetPos = Args.begin() + 1;
- Value* OffsetVal = *OffsetPos;
- Args.erase(OffsetPos);
- Args.push_back(OffsetVal);
- }
- break;
- default:
- assert(0 && "Invalid number of arguments");
- }
- // Translate ndrange_ND into differently named SPIR-V decorated functions because
- // they have array arugments of different dimension which mangled the same way.
- return getSPIRVFuncName(OpBuildNDRange, "_" + lenStr + "D");
- }, &Attrs);
-}
-
-void
-OCL20ToSPIRV::visitCallAsyncWorkGroupCopy(CallInst* CI,
- const std::string &DemangledName) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args){
- if (DemangledName == OCLUtil::kOCLBuiltinName::AsyncWorkGroupCopy) {
- Args.insert(Args.begin()+3, addSizet(1));
- }
- Args.insert(Args.begin(), addInt32(ScopeWorkgroup));
- return getSPIRVFuncName(OpGroupAsyncCopy);
- }, &Attrs);
-}
-
-CallInst *
-OCL20ToSPIRV::visitCallAtomicCmpXchg(CallInst* CI,
- const std::string& DemangledName) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- Value *Expected = nullptr;
- CallInst *NewCI = nullptr;
- mutateCallInstOCL(M, CI, [&](CallInst * CI, std::vector<Value *> &Args,
- Type *&RetTy){
- Expected = Args[1]; // temporary save second argument.
- Args[1] = new LoadInst(Args[1], "exp", false, CI);
- RetTy = Args[2]->getType();
- assert(Args[0]->getType()->getPointerElementType()->isIntegerTy() &&
- Args[1]->getType()->isIntegerTy() && Args[2]->getType()->isIntegerTy() &&
- "In SPIR-V 1.0 arguments of OpAtomicCompareExchange must be "
- "an integer type scalars");
- return kOCLBuiltinName::AtomicCmpXchgStrong;
- },
- [&](CallInst *NCI)->Instruction * {
- NewCI = NCI;
- Instruction* Store = new StoreInst(NCI, Expected, NCI->getNextNode());
- return new ICmpInst(Store->getNextNode(), CmpInst::ICMP_EQ, NCI,
- NCI->getArgOperand(1));
- },
- &Attrs);
- return NewCI;
-}
-
-void
-OCL20ToSPIRV::visitCallAtomicInit(CallInst* CI) {
- auto ST = new StoreInst(CI->getArgOperand(1), CI->getArgOperand(0), CI);
- ST->takeName(CI);
- CI->dropAllReferences();
- CI->eraseFromParent();
-}
-
-void
-OCL20ToSPIRV::visitCallAllAny(spv::Op OC, CallInst* CI) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
-
- auto Args = getArguments(CI);
- assert(Args.size() == 1);
-
- auto *ArgTy = Args[0]->getType();
- auto Zero = Constant::getNullValue(Args[0]->getType());
-
- auto *Cmp = CmpInst::Create(CmpInst::ICmp, CmpInst::ICMP_SLT, Args[0], Zero,
- "cast", CI);
-
- if (!isa<VectorType>(ArgTy)) {
- auto *Cast = CastInst::CreateZExtOrBitCast(Cmp, Type::getInt32Ty(*Ctx),
- "", Cmp->getNextNode());
- CI->replaceAllUsesWith(Cast);
- CI->eraseFromParent();
- } else {
- mutateCallInstSPIRV(
- M, CI,
- [&](CallInst *, std::vector<Value *> &Args, Type *&Ret) {
- Args[0] = Cmp;
- Ret = Type::getInt1Ty(*Ctx);
-
- return getSPIRVFuncName(OC);
- },
- [&](CallInst *CI) -> Instruction * {
- return CastInst::CreateZExtOrBitCast(CI, Type::getInt32Ty(*Ctx), "",
- CI->getNextNode());
- },
- &Attrs);
- }
-}
-
-void
-OCL20ToSPIRV::visitCallAtomicWorkItemFence(CallInst* CI) {
- transMemoryBarrier(CI, getAtomicWorkItemFenceLiterals(CI));
-}
-
-void
-OCL20ToSPIRV::visitCallMemFence(CallInst* CI) {
- transMemoryBarrier(CI, std::make_tuple(
- cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue(),
- OCLMO_relaxed,
- OCLMS_work_group));
-}
-
-void OCL20ToSPIRV::transMemoryBarrier(CallInst* CI,
- AtomicWorkItemFenceLiterals Lit) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args){
- Args.resize(2);
- Args[0] = addInt32(map<Scope>(std::get<2>(Lit)));
- Args[1] = addInt32(mapOCLMemSemanticToSPIRV(std::get<0>(Lit),
- std::get<1>(Lit)));
- return getSPIRVFuncName(OpMemoryBarrier);
- }, &Attrs);
-}
-
-void
-OCL20ToSPIRV::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
-OCL20ToSPIRV::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
-OCL20ToSPIRV::transAtomicBuiltin(CallInst* CI,
- OCLBuiltinTransInfo& Info) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- mutateCallInstSPIRV(M, CI, [=](CallInst * CI, std::vector<Value *> &Args){
- Info.PostProc(Args);
- // Order of args in OCL20:
- // object, 0-2 other args, 1-2 order, scope
- const size_t NumOrder = getAtomicBuiltinNumMemoryOrderArgs(Info.UniqName);
- const size_t ArgsCount = Args.size();
- const size_t ScopeIdx = ArgsCount - 1;
- const size_t OrderIdx = ScopeIdx - NumOrder;
- Args[ScopeIdx] = mapUInt(M, cast<ConstantInt>(Args[ScopeIdx]),
- [](unsigned I){
- return map<Scope>(static_cast<OCLScopeKind>(I));
- });
- for (size_t I = 0; I < NumOrder; ++I)
- Args[OrderIdx + I] = mapUInt(M, cast<ConstantInt>(Args[OrderIdx + I]),
- [](unsigned Ord) {
- return mapOCLMemSemanticToSPIRV(0, static_cast<OCLMemOrderKind>(Ord));
- });
- // Order of args in SPIR-V:
- // object, scope, 1-2 order, 0-2 other args
- std::swap(Args[1], Args[ScopeIdx]);
- if(OrderIdx > 2) {
- // For atomic_compare_exchange the swap above puts Comparator/Expected
- // argument just where it should be, so don't move the last argument then.
- int offset = Info.UniqName.find("atomic_compare_exchange") == 0 ? 1 : 0;
- std::rotate(Args.begin() + 2, Args.begin() + OrderIdx,
- Args.end() - offset);
- }
- return getSPIRVFuncName(OCLSPIRVBuiltinMap::map(Info.UniqName));
- }, &Attrs);
-}
-
-void
-OCL20ToSPIRV::visitCallBarrier(CallInst* CI) {
- auto Lit = getBarrierLiterals(CI);
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args){
- Args.resize(3);
- Args[0] = addInt32(map<Scope>(std::get<2>(Lit)));
- Args[1] = addInt32(map<Scope>(std::get<1>(Lit)));
- Args[2] = addInt32(mapOCLMemFenceFlagToSPIRV(std::get<0>(Lit)));
- return getSPIRVFuncName(OpControlBarrier);
- }, &Attrs);
-}
-
-void OCL20ToSPIRV::visitCallConvert(CallInst* CI,
- StringRef MangledName, const std::string& DemangledName) {
- if (eraseUselessConvert(CI, MangledName, DemangledName))
- return;
- Op OC = OpNop;
- auto TargetTy = CI->getType();
- auto SrcTy = CI->getArgOperand(0)->getType();
- if (isa<VectorType>(TargetTy))
- TargetTy = TargetTy->getVectorElementType();
- if (isa<VectorType>(SrcTy))
- SrcTy = SrcTy->getVectorElementType();
- auto IsTargetInt = isa<IntegerType>(TargetTy);
-
- std::string TargetTyName = DemangledName.substr(
- strlen(kOCLBuiltinName::ConvertPrefix));
- auto FirstUnderscoreLoc = TargetTyName.find('_');
- if (FirstUnderscoreLoc != std::string::npos)
- TargetTyName = TargetTyName.substr(0, FirstUnderscoreLoc);
- TargetTyName = std::string("_R") + TargetTyName;
-
- std::string Sat = DemangledName.find("_sat") != std::string::npos ?
- "_sat" : "";
- auto TargetSigned = DemangledName[8] != 'u';
- if (isa<IntegerType>(SrcTy)) {
- bool Signed = isLastFuncParamSigned(MangledName);
- if (IsTargetInt) {
- if (!Sat.empty() && TargetSigned != Signed) {
- OC = Signed ? OpSatConvertSToU : OpSatConvertUToS;
- Sat = "";
- } else
- OC = Signed ? OpSConvert : OpUConvert;
- } else
- OC = Signed ? OpConvertSToF : OpConvertUToF;
- } else {
- if (IsTargetInt) {
- OC = TargetSigned ? OpConvertFToS : OpConvertFToU;
- } else
- OC = OpFConvert;
- }
- auto Loc = DemangledName.find("_rt");
- std::string Rounding;
- if (Loc != std::string::npos &&
- !(isa<IntegerType>(SrcTy) && IsTargetInt)) {
- Rounding = DemangledName.substr(Loc, 4);
- }
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args){
- return getSPIRVFuncName(OC, TargetTyName + Sat + Rounding);
- }, &Attrs);
-}
-
-void OCL20ToSPIRV::visitCallGroupBuiltin(CallInst* CI,
- StringRef MangledName, const std::string& OrigDemangledName) {
- auto F = CI->getCalledFunction();
- std::vector<int> PreOps;
- std::string DemangledName = OrigDemangledName;
-
- if (DemangledName == kOCLBuiltinName::WorkGroupBarrier)
- return;
- if (DemangledName == kOCLBuiltinName::WaitGroupEvent) {
- PreOps.push_back(ScopeWorkgroup);
- } else if (DemangledName.find(kOCLBuiltinName::WorkGroupPrefix) == 0) {
- DemangledName.erase(0, strlen(kOCLBuiltinName::WorkPrefix));
- PreOps.push_back(ScopeWorkgroup);
- } else if (DemangledName.find(kOCLBuiltinName::SubGroupPrefix) == 0) {
- DemangledName.erase(0, strlen(kOCLBuiltinName::SubPrefix));
- PreOps.push_back(ScopeSubgroup);
- } else
- return;
-
- if (DemangledName != kOCLBuiltinName::WaitGroupEvent) {
- StringRef GroupOp = DemangledName;
- GroupOp = GroupOp.drop_front(strlen(kSPIRVName::GroupPrefix));
- SPIRSPIRVGroupOperationMap::foreach_conditional([&](const std::string &S,
- SPIRVGroupOperationKind G){
- if (!GroupOp.startswith(S))
- return true; // continue
- PreOps.push_back(G);
- StringRef Op = GroupOp.drop_front(S.size() + 1);
- assert(!Op.empty() && "Invalid OpenCL group builtin function");
- char OpTyC = 0;
- auto NeedSign = Op == "max" || Op == "min";
- auto OpTy = F->getReturnType();
- if (OpTy->isFloatingPointTy())
- OpTyC = 'f';
- else if (OpTy->isIntegerTy()) {
- if (!NeedSign)
- OpTyC = 'i';
- else {
- if (isLastFuncParamSigned(F->getName()))
- OpTyC = 's';
- else
- OpTyC = 'u';
- }
- } else
- llvm_unreachable("Invalid OpenCL group builtin argument type");
-
- DemangledName = std::string(kSPIRVName::GroupPrefix) + OpTyC + Op.str();
- return false; // break out of loop
- });
- }
-
- bool IsGroupAllAny = (DemangledName.find("_all") != std::string::npos ||
- DemangledName.find("_any") != std::string::npos);
-
- auto Consts = getInt32(M, PreOps);
- OCLBuiltinTransInfo Info;
- if (IsGroupAllAny)
- Info.RetTy = Type::getInt1Ty(*Ctx);
- Info.UniqName = DemangledName;
- Info.PostProc = [=](std::vector<Value *> &Ops) {
- if (IsGroupAllAny) {
- IRBuilder<> IRB(CI);
- Ops[0] =
- IRB.CreateICmpNE(Ops[0], ConstantInt::get(Type::getInt32Ty(*Ctx), 0));
- }
- size_t E = Ops.size();
- if (DemangledName == "group_broadcast" && E > 2) {
- assert(E == 3 || E == 4);
- makeVector(CI, Ops, std::make_pair(Ops.begin() + 1, Ops.end()));
- }
- Ops.insert(Ops.begin(), Consts.begin(), Consts.end());
- };
- transBuiltin(CI, Info);
-}
-
-void
-OCL20ToSPIRV::transBuiltin(CallInst* CI,
- OCLBuiltinTransInfo& Info) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- Op OC = OpNop;
- unsigned ExtOp = ~0U;
- if (StringRef(Info.UniqName).startswith(kSPIRVName::Prefix))
- return;
- if (OCLSPIRVBuiltinMap::find(Info.UniqName, &OC))
- Info.UniqName = getSPIRVFuncName(OC);
- else if ((ExtOp = getExtOp(Info.MangledName, Info.UniqName)) != ~0U)
- Info.UniqName = getSPIRVExtFuncName(SPIRVEIS_OpenCL, ExtOp);
- else
- return;
- if (!Info.RetTy)
- mutateCallInstSPIRV(M, CI,
- [=](CallInst *, std::vector<Value *> &Args) {
- Info.PostProc(Args);
- return Info.UniqName + Info.Postfix;
- },
- &Attrs);
- else
- mutateCallInstSPIRV(
- M, CI,
- [=](CallInst *, std::vector<Value *> &Args, Type *&RetTy) {
- Info.PostProc(Args);
- RetTy = Info.RetTy;
- return Info.UniqName + Info.Postfix;
- },
- [=](CallInst *NewCI) -> Instruction * {
- if (NewCI->getType()->isIntegerTy() && CI->getType()->isIntegerTy())
- return CastInst::CreateIntegerCast(NewCI, CI->getType(),
- Info.isRetSigned, "", CI);
- else
- return CastInst::CreatePointerBitCastOrAddrSpaceCast(
- NewCI, CI->getType(), "", CI);
- },
- &Attrs);
-}
-
-void
-OCL20ToSPIRV::visitCallPipeBuiltin(CallInst* CI,
- StringRef MangledName, const std::string& DemangledName) {
- std::string NewName = DemangledName;
- // Transform OpenCL read_pipe/write_pipe builtin function names
- // with reserve_id argument to reserved_read_pipe/reserved_write_pipe.
- if ((DemangledName.find(kOCLBuiltinName::ReadPipe) == 0 ||
- DemangledName.find(kOCLBuiltinName::WritePipe) == 0)
- && CI->getNumArgOperands() > 4)
- NewName = std::string(kSPIRVName::ReservedPrefix) + DemangledName;
- OCLBuiltinTransInfo Info;
- Info.UniqName = NewName;
- transBuiltin(CI, Info);
-}
-
-void OCL20ToSPIRV::visitCallReadImageMSAA(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName) {
- assert(MangledName.find("msaa") != StringRef::npos);
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- mutateCallInstSPIRV(
- M, CI,
- [=](CallInst *, std::vector<Value *> &Args) {
- Args.insert(Args.begin() + 2, getInt32(M, ImageOperandsSampleMask));
- return getSPIRVFuncName(OpImageRead,
- std::string(kSPIRVPostfix::ExtDivider) +
- getPostfixForReturnType(CI));
- },
- &Attrs);
-}
-
-void OCL20ToSPIRV::visitCallReadImageWithSampler(
- CallInst *CI, StringRef MangledName, const std::string &DemangledName) {
- assert (MangledName.find(kMangledName::Sampler) != StringRef::npos);
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- bool isRetScalar = !CI->getType()->isVectorTy();
- mutateCallInstSPIRV(
- M, CI,
- [=](CallInst *, std::vector<Value *> &Args, Type *&Ret) {
- auto ImageTy = getAnalysis<OCLTypeToSPIRV>().getAdaptedType(Args[0]);
- if (isOCLImageType(ImageTy))
- ImageTy = getSPIRVImageTypeFromOCL(M, ImageTy);
- auto SampledImgTy = getSPIRVTypeByChangeBaseTypeName(
- M, ImageTy, kSPIRVTypeName::Image, kSPIRVTypeName::SampledImg);
- Value *SampledImgArgs[] = {Args[0], Args[1]};
- auto SampledImg = addCallInstSPIRV(
- M, getSPIRVFuncName(OpSampledImage), SampledImgTy, SampledImgArgs,
- nullptr, CI, kSPIRVName::TempSampledImage);
-
- Args[0] = SampledImg;
- Args.erase(Args.begin() + 1, Args.begin() + 2);
-
- switch (Args.size()) {
- case 2: // no lod
- Args.push_back(getInt32(M, ImageOperandsMask::ImageOperandsLodMask));
- Args.push_back(getFloat32(M, 0.f));
- break;
- case 3: // explicit lod
- Args.insert(Args.begin() + 2,
- getInt32(M, ImageOperandsMask::ImageOperandsLodMask));
- break;
- case 4: // gradient
- Args.insert(Args.begin() + 2,
- getInt32(M, ImageOperandsMask::ImageOperandsGradMask));
- break;
- default:
- assert(0 && "read_image* with unhandled number of args!");
- }
-
- // SPIR-V intruction always returns 4-element vector
- if (isRetScalar)
- Ret = VectorType::get(Ret, 4);
- return getSPIRVFuncName(OpImageSampleExplicitLod,
- std::string(kSPIRVPostfix::ExtDivider) +
- getPostfixForReturnType(Ret));
- },
- [&](CallInst *CI) -> Instruction * {
- if (isRetScalar)
- return ExtractElementInst::Create(CI, getSizet(M, 0), "",
- CI->getNextNode());
- return CI;
- },
- &Attrs);
-}
-
-void
-OCL20ToSPIRV::visitCallGetImageSize(CallInst* CI,
- StringRef MangledName, const std::string& DemangledName) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- StringRef TyName;
- SmallVector<StringRef, 4> SubStrs;
- auto IsImg = isOCLImageType(CI->getArgOperand(0)->getType(), &TyName);
- (void)IsImg;
- assert(IsImg);
- std::string ImageTyName = TyName.str();
- if (hasAccessQualifiedName(TyName))
- ImageTyName.erase(ImageTyName.size() - 5, 3);
- auto Desc = map<SPIRVTypeImageDescriptor>(ImageTyName);
- unsigned Dim = getImageDimension(Desc.Dim) + Desc.Arrayed;
- assert(Dim > 0 && "Invalid image dimension.");
- mutateCallInstSPIRV(M, CI,
- [&](CallInst *, std::vector<Value *> &Args, Type *&Ret){
- assert(Args.size() == 1);
- Ret = CI->getType()->isIntegerTy(64) ? Type::getInt64Ty(*Ctx)
- : Type::getInt32Ty(*Ctx);
- if (Dim > 1)
- Ret = VectorType::get(Ret, Dim);
- if (Desc.Dim == DimBuffer)
- return getSPIRVFuncName(OpImageQuerySize, CI->getType());
- else {
- Args.push_back(getInt32(M, 0));
- return getSPIRVFuncName(OpImageQuerySizeLod, CI->getType());
- }
- },
- [&](CallInst *NCI)->Instruction * {
- if (Dim == 1)
- return NCI;
- if (DemangledName == kOCLBuiltinName::GetImageDim) {
- if (Desc.Dim == Dim3D) {
- auto ZeroVec = ConstantVector::getSplat(3,
- Constant::getNullValue(NCI->getType()->getVectorElementType()));
- Constant *Index[] = {getInt32(M, 0), getInt32(M, 1),
- getInt32(M, 2), getInt32(M, 3)};
- return new ShuffleVectorInst(NCI, ZeroVec,
- ConstantVector::get(Index), "", CI);
-
- } else if (Desc.Dim == Dim2D && Desc.Arrayed) {
- Constant *Index[] = {getInt32(M, 0), getInt32(M, 1)};
- Constant *mask = ConstantVector::get(Index);
- return new ShuffleVectorInst(NCI, UndefValue::get(NCI->getType()),
- mask, NCI->getName(), CI);
- }
- return NCI;
- }
- unsigned I = StringSwitch<unsigned>(DemangledName)
- .Case(kOCLBuiltinName::GetImageWidth, 0)
- .Case(kOCLBuiltinName::GetImageHeight, 1)
- .Case(kOCLBuiltinName::GetImageDepth, 2)
- .Case(kOCLBuiltinName::GetImageArraySize, Dim - 1);
- return ExtractElementInst::Create(NCI, getUInt32(M, I), "",
- NCI->getNextNode());
- },
- &Attrs);
-}
-
-/// Remove trivial conversion functions
-bool
-OCL20ToSPIRV::eraseUselessConvert(CallInst *CI,
- const std::string &MangledName,
- const std::string &DemangledName) {
- auto TargetTy = CI->getType();
- auto SrcTy = CI->getArgOperand(0)->getType();
- if (isa<VectorType>(TargetTy))
- TargetTy = TargetTy->getVectorElementType();
- if (isa<VectorType>(SrcTy))
- SrcTy = SrcTy->getVectorElementType();
- if (TargetTy == SrcTy) {
- if (isa<IntegerType>(TargetTy) &&
- DemangledName.find("_sat") != std::string::npos &&
- isLastFuncParamSigned(MangledName) != (DemangledName[8] != 'u'))
- return false;
- CI->getArgOperand(0)->takeName(CI);
- SPIRVDBG(dbgs() << "[regularizeOCLConvert] " << *CI << " <- " <<
- *CI->getArgOperand(0) << '\n');
- CI->replaceAllUsesWith(CI->getArgOperand(0));
- ValuesToDelete.insert(CI);
- ValuesToDelete.insert(CI->getCalledFunction());
- return true;
- }
- return false;
-}
-
-void
-OCL20ToSPIRV::visitCallBuiltinSimple(CallInst* CI,
- StringRef MangledName, const std::string& DemangledName) {
- OCLBuiltinTransInfo Info;
- Info.MangledName = MangledName.str();
- Info.UniqName = DemangledName;
- transBuiltin(CI, Info);
-}
-
-/// Translates OCL work-item builtin functions to SPIRV builtin variables.
-/// Function like get_global_id(i) -> x = load GlobalInvocationId; extract x, i
-/// Function like get_work_dim() -> load WorkDim
-void OCL20ToSPIRV::transWorkItemBuiltinsToVariables() {
- DEBUG(dbgs() << "Enter transWorkItemBuiltinsToVariables\n");
- std::vector<Function *> WorkList;
- for (auto &I:*M) {
- std::string DemangledName;
- if (!oclIsBuiltin(I.getName(), &DemangledName))
- continue;
- DEBUG(dbgs() << "Function demangled name: " << DemangledName << '\n');
- std::string BuiltinVarName;
- SPIRVBuiltinVariableKind BVKind;
- if (!SPIRSPIRVBuiltinVariableMap::find(DemangledName, &BVKind))
- continue;
- BuiltinVarName = std::string(kSPIRVName::Prefix) +
- SPIRVBuiltInNameMap::map(BVKind);
- DEBUG(dbgs() << "builtin variable name: " << BuiltinVarName << '\n');
- bool IsVec = I.getFunctionType()->getNumParams() > 0;
- Type *GVType = IsVec ? VectorType::get(I.getReturnType(),3) :
- I.getReturnType();
- auto BV = new GlobalVariable(*M, GVType,
- true,
- GlobalValue::ExternalLinkage,
- nullptr, BuiltinVarName,
- 0,
- GlobalVariable::NotThreadLocal,
- SPIRAS_Constant);
- std::vector<Instruction *> InstList;
- for (auto UI = I.user_begin(), UE = I.user_end(); UI != UE; ++UI) {
- auto CI = dyn_cast<CallInst>(*UI);
- assert(CI && "invalid instruction");
- Value * NewValue = new LoadInst(BV, "", CI);
- DEBUG(dbgs() << "Transform: " << *CI << " => " << *NewValue << '\n');
- if (IsVec) {
- NewValue = ExtractElementInst::Create(NewValue,
- CI->getArgOperand(0),
- "", CI);
- DEBUG(dbgs() << *NewValue << '\n');
- }
- NewValue->takeName(CI);
- CI->replaceAllUsesWith(NewValue);
- InstList.push_back(CI);
- }
- for (auto &Inst:InstList) {
- Inst->eraseFromParent();
- }
- WorkList.push_back(&I);
- }
- for (auto &I:WorkList) {
- I->eraseFromParent();
- }
-}
-
-void
-OCL20ToSPIRV::visitCallReadWriteImage(CallInst* CI,
- StringRef MangledName, const std::string& DemangledName) {
- OCLBuiltinTransInfo Info;
- if (DemangledName.find(kOCLBuiltinName::ReadImage) == 0)
- Info.UniqName = kOCLBuiltinName::ReadImage;
-
- if (DemangledName.find(kOCLBuiltinName::WriteImage) == 0)
- {
- Info.UniqName = kOCLBuiltinName::WriteImage;
- Info.PostProc = [&](std::vector<Value*> &Args) {
- if (Args.size() == 4) // write with lod
- {
- auto Lod = Args[2];
- Args.erase(Args.begin() + 2);
- Args.push_back(getInt32(M, ImageOperandsMask::ImageOperandsLodMask));
- Args.push_back(Lod);
- }
- };
- }
-
- transBuiltin(CI, Info);
-}
-
-void
-OCL20ToSPIRV::visitCallToAddr(CallInst* CI, StringRef MangledName,
- const std::string &DemangledName) {
- auto AddrSpace = static_cast<SPIRAddressSpace>(
- CI->getType()->getPointerAddressSpace());
- OCLBuiltinTransInfo Info;
- Info.UniqName = DemangledName;
- Info.Postfix = std::string(kSPIRVPostfix::Divider) + "To" +
- SPIRAddrSpaceCapitalizedNameMap::map(AddrSpace);
- auto StorageClass = addInt32(SPIRSPIRVAddrSpaceMap::map(AddrSpace));
- Info.RetTy = getInt8PtrTy(cast<PointerType>(CI->getType()));
- Info.PostProc = [=](std::vector<Value *> &Ops){
- auto P = Ops.back();
- Ops.pop_back();
- Ops.push_back(castToInt8Ptr(P, CI));
- Ops.push_back(StorageClass);
- };
- transBuiltin(CI, Info);
-}
-
-void OCL20ToSPIRV::visitCallRelational(CallInst *CI,
- const std::string &DemangledName) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- Op OC = OpNop;
- OCLSPIRVBuiltinMap::find(DemangledName, &OC);
- std::string SPIRVName = getSPIRVFuncName(OC);
- mutateCallInstSPIRV(
- M, CI,
- [=](CallInst *, std::vector<Value *> &Args, Type *&Ret) {
- Ret = Type::getInt1Ty(*Ctx);
- if (CI->getOperand(0)->getType()->isVectorTy())
- Ret = VectorType::get(
- Type::getInt1Ty(*Ctx),
- CI->getOperand(0)->getType()->getVectorNumElements());
- return SPIRVName;
- },
- [=](CallInst *NewCI) -> Instruction * {
- Value *False = nullptr, *True = nullptr;
- if (NewCI->getType()->isVectorTy()) {
- Type *IntTy = Type::getInt32Ty(*Ctx);
- if (cast<VectorType>(NewCI->getOperand(0)->getType())
- ->getElementType()
- ->isDoubleTy())
- IntTy = Type::getInt64Ty(*Ctx);
- if (cast<VectorType>(NewCI->getOperand(0)->getType())
- ->getElementType()
- ->isHalfTy())
- IntTy = Type::getInt16Ty(*Ctx);
- Type *VTy = VectorType::get(IntTy,
- NewCI->getType()->getVectorNumElements());
- False = Constant::getNullValue(VTy);
- True = Constant::getAllOnesValue(VTy);
- } else {
- False = getInt32(M, 0);
- True = getInt32(M, 1);
- }
- return SelectInst::Create(NewCI, True, False, "", NewCI->getNextNode());
- },
- &Attrs);
-}
-
-void
-OCL20ToSPIRV::visitCallVecLoadStore(CallInst* CI,
- StringRef MangledName, const std::string& OrigDemangledName) {
- std::vector<int> PreOps;
- std::string DemangledName = OrigDemangledName;
- if (DemangledName.find(kOCLBuiltinName::VLoadPrefix) == 0 &&
- DemangledName != kOCLBuiltinName::VLoadHalf) {
- SPIRVWord Width = getVecLoadWidth(DemangledName);
- SPIRVDBG(spvdbgs() << "[visitCallVecLoadStore] DemangledName: " <<
- DemangledName << " Width: " << Width << '\n');
- PreOps.push_back(Width);
- } else if (DemangledName.find(kOCLBuiltinName::RoundingPrefix)
- != std::string::npos) {
- auto R = SPIRSPIRVFPRoundingModeMap::map(DemangledName.substr(
- DemangledName.find(kOCLBuiltinName::RoundingPrefix) + 1, 3));
- PreOps.push_back(R);
- }
-
- if (DemangledName.find(kOCLBuiltinName::VLoadAPrefix) == 0)
- transVecLoadStoreName(DemangledName, kOCLBuiltinName::VLoadAPrefix, true);
- else
- transVecLoadStoreName(DemangledName, kOCLBuiltinName::VLoadPrefix, false);
-
- if (DemangledName.find(kOCLBuiltinName::VStoreAPrefix) == 0)
- transVecLoadStoreName(DemangledName, kOCLBuiltinName::VStoreAPrefix, true);
- else
- transVecLoadStoreName(DemangledName, kOCLBuiltinName::VStorePrefix, false);
-
-
- auto Consts = getInt32(M, PreOps);
- OCLBuiltinTransInfo Info;
- Info.MangledName = MangledName;
- Info.UniqName = DemangledName;
- if (DemangledName.find(kOCLBuiltinName::VLoadPrefix) == 0)
- Info.Postfix = std::string(kSPIRVPostfix::ExtDivider) +
- getPostfixForReturnType(CI);
- Info.PostProc = [=](std::vector<Value *> &Ops){
- Ops.insert(Ops.end(), Consts.begin(), Consts.end());
- };
- transBuiltin(CI, Info);
-}
-
-void OCL20ToSPIRV::visitCallGetFence(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- Op OC = OpNop;
- OCLSPIRVBuiltinMap::find(DemangledName, &OC);
- std::string SPIRVName = getSPIRVFuncName(OC);
- mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args,
- Type *&Ret) { return SPIRVName; },
- [=](CallInst *NewCI) -> Instruction * {
- return BinaryOperator::CreateLShr(NewCI, getInt32(M, 8), "", CI);
- },
- &Attrs);
-}
-
-void OCL20ToSPIRV::visitCallDot(CallInst *CI) {
- IRBuilder<> Builder(CI);
- Value *FMulVal = Builder.CreateFMul(CI->getOperand(0), CI->getOperand(1));
- CI->replaceAllUsesWith(FMulVal);
- CI->eraseFromParent();
-}
-
-void OCL20ToSPIRV::visitCallScalToVec(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName) {
- // Check if all arguments have the same type - it's simple case.
- auto Uniform = true;
- auto IsArg0Vector = isa<VectorType>(CI->getOperand(0)->getType());
- for (unsigned I = 1, E = CI->getNumArgOperands(); Uniform && (I != E); ++I) {
- Uniform = isa<VectorType>(CI->getOperand(I)->getType()) == IsArg0Vector;
- }
- if (Uniform) {
- visitCallBuiltinSimple(CI, MangledName, DemangledName);
- return;
- }
-
- std::vector<unsigned int> VecPos;
- std::vector<unsigned int> ScalarPos;
- if (DemangledName == kOCLBuiltinName::FMin ||
- DemangledName == kOCLBuiltinName::FMax ||
- DemangledName == kOCLBuiltinName::Min ||
- DemangledName == kOCLBuiltinName::Max) {
- VecPos.push_back(0);
- ScalarPos.push_back(1);
- } else if (DemangledName == kOCLBuiltinName::Clamp) {
- VecPos.push_back(0);
- ScalarPos.push_back(1);
- ScalarPos.push_back(2);
- } else if (DemangledName == kOCLBuiltinName::Mix) {
- VecPos.push_back(0);
- VecPos.push_back(1);
- ScalarPos.push_back(2);
- } else if (DemangledName == kOCLBuiltinName::Step) {
- VecPos.push_back(1);
- ScalarPos.push_back(0);
- } else if (DemangledName == kOCLBuiltinName::SmoothStep) {
- VecPos.push_back(2);
- ScalarPos.push_back(0);
- ScalarPos.push_back(1);
- }
-
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- mutateCallInstSPIRV(
- M, CI,
- [=](CallInst *, std::vector<Value *> &Args) {
- Args.resize(VecPos.size() + ScalarPos.size());
- for (auto I : VecPos) {
- Args[I] = CI->getOperand(I);
- }
- auto VecArgWidth =
- CI->getOperand(VecPos[0])->getType()->getVectorNumElements();
- for (auto I : ScalarPos) {
- Instruction *Inst = InsertElementInst::Create(
- UndefValue::get(CI->getOperand(VecPos[0])->getType()),
- CI->getOperand(I), getInt32(M, 0), "", CI);
- Value *NewVec = new ShuffleVectorInst(
- Inst, UndefValue::get(CI->getOperand(VecPos[0])->getType()),
- ConstantVector::getSplat(VecArgWidth, getInt32(M, 0)), "", CI);
-
- Args[I] = NewVec;
- }
- return getSPIRVExtFuncName(SPIRVEIS_OpenCL,
- getExtOp(MangledName, DemangledName));
- },
- &Attrs);
-}
-
-void OCL20ToSPIRV::visitCallGetImageChannel(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName,
- unsigned int Offset) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- Op OC = OpNop;
- OCLSPIRVBuiltinMap::find(DemangledName, &OC);
- std::string SPIRVName = getSPIRVFuncName(OC);
- mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args,
- Type *&Ret) { return SPIRVName; },
- [=](CallInst *NewCI) -> Instruction * {
- return BinaryOperator::CreateAdd(
- NewCI, getInt32(M, Offset), "", CI);
- },
- &Attrs);
-}
-
-// The intel_sub_group_block_read built-ins are overloaded to support both
-// buffers and images, but need to be mapped to distinct SPIR-V instructions.
-// Additionally, for block reads, need to distinguish between scalar block
-// reads and vector block reads.
-void OCL20ToSPIRV::visitSubgroupBlockReadINTEL(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName) {
- OCLBuiltinTransInfo Info;
- if (isOCLImageType(CI->getArgOperand(0)->getType()))
- Info.UniqName = getSPIRVFuncName(spv::OpSubgroupImageBlockReadINTEL);
- else
- Info.UniqName = getSPIRVFuncName(spv::OpSubgroupBlockReadINTEL);
- if (CI->getType()->isVectorTy()) {
- switch(CI->getType()->getVectorNumElements()) {
- case 2: Info.Postfix = "_v2"; break;
- case 4: Info.Postfix = "_v4"; break;
- case 8: Info.Postfix = "_v8"; break;
- default: break;
- }
- }
- if (CI->getType()->getScalarSizeInBits() == 16)
- Info.Postfix += "_us";
- else
- Info.Postfix += "_ui";
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- mutateCallInstSPIRV(M, CI,
- [=](CallInst *, std::vector<Value *> &Args) {
- Info.PostProc(Args);
- return Info.UniqName + Info.Postfix;
- },
- &Attrs);
-}
-
-// The intel_sub_group_block_write built-ins are similarly overloaded to support
-// both buffers and images but need to be mapped to distinct SPIR-V instructions.
-// Since the type of data to be written is encoded in the mangled name there is
-// no need to do additional work to distinguish between scalar block writes and
-// vector block writes.
-void OCL20ToSPIRV::visitSubgroupBlockWriteINTEL(CallInst *CI, StringRef MangledName,
- const std::string &DemangledName) {
- OCLBuiltinTransInfo Info;
- if (isOCLImageType(CI->getArgOperand(0)->getType()))
- Info.UniqName = getSPIRVFuncName(spv::OpSubgroupImageBlockWriteINTEL);
- else
- Info.UniqName = getSPIRVFuncName(spv::OpSubgroupBlockWriteINTEL);
- unsigned numArgs = CI->getNumArgOperands();
- if (numArgs && CI->getArgOperand(numArgs - 1)->getType()->isVectorTy()) {
- switch(CI->getArgOperand(numArgs - 1)->getType()->getVectorNumElements()) {
- case 2: Info.Postfix = "_v2"; break;
- case 4: Info.Postfix = "_v4"; break;
- case 8: Info.Postfix = "_v8"; break;
- default: break;
- }
- }
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- mutateCallInstSPIRV(M, CI,
- [=](CallInst *, std::vector<Value *> &Args) {
- Info.PostProc(Args);
- return Info.UniqName + Info.Postfix;
- },
- &Attrs);
-}
-
-}
-
-INITIALIZE_PASS_BEGIN(OCL20ToSPIRV, "cl20tospv", "Transform OCL 2.0 to SPIR-V",
- false, false)
-INITIALIZE_PASS_DEPENDENCY(OCLTypeToSPIRV)
-INITIALIZE_PASS_END(OCL20ToSPIRV, "cl20tospv", "Transform OCL 2.0 to SPIR-V",
- false, false)
-
-ModulePass *llvm::createOCL20ToSPIRV() {
- return new OCL20ToSPIRV();
-}
+//===- OCL20ToSPIRV.cpp - Transform OCL20 to SPIR-V builtins -----*- 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 implements translation of OCL20 builtin functions. +// +//===----------------------------------------------------------------------===// +#define DEBUG_TYPE "cl20tospv" + +#include "SPIRVInternal.h" +#include "OCLUtil.h" +#include "OCLTypeToSPIRV.h" + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/IR/InstVisitor.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Instruction.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" + +#include <set> + +using namespace llvm; +using namespace SPIRV; +using namespace OCLUtil; + +namespace SPIRV { +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 OCL20ToSPIRV: public ModulePass, + public InstVisitor<OCL20ToSPIRV> { +public: + OCL20ToSPIRV():ModulePass(ID), M(nullptr), Ctx(nullptr), CLVer(0) { + initializeOCL20ToSPIRVPass(*PassRegistry::getPassRegistry()); + } + virtual bool runOnModule(Module &M); + + void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<OCLTypeToSPIRV>(); + } + + virtual void visitCallInst(CallInst &CI); + + /// Transform barrier/work_group_barrier/sub_group_barrier + /// to __spirv_ControlBarrier. + /// barrier(flag) => + /// __spirv_ControlBarrier(workgroup, workgroup, map(flag)) + /// work_group_barrier(scope, flag) => + /// __spirv_ControlBarrier(workgroup, map(scope), map(flag)) + /// sub_group_barrier(scope, flag) => + /// __spirv_ControlBarrier(subgroup, map(scope), map(flag)) + void visitCallBarrier(CallInst *CI); + + /// Erase useless convert functions. + /// \return true if the call instruction is erased. + bool eraseUselessConvert(CallInst *Call, const std::string &MangledName, + const std::string &DeMangledName); + + /// Transform convert_ to + /// __spirv_{CastOpName}_R{TargeTyName}{_sat}{_rt[p|n|z|e]} + void visitCallConvert(CallInst *CI, StringRef MangledName, + const std::string &DemangledName); + + /// Transform async_work_group{_strided}_copy. + /// async_work_group_copy(dst, src, n, event) + /// => async_work_group_strided_copy(dst, src, n, 1, event) + /// async_work_group_strided_copy(dst, src, n, stride, event) + /// => __spirv_AsyncGroupCopy(ScopeWorkGroup, dst, src, n, stride, event) + void visitCallAsyncWorkGroupCopy(CallInst *CI, + const std::string &DemangledName); + + /// Transform OCL builtin function to SPIR-V builtin function. + void transBuiltin(CallInst *CI, OCLBuiltinTransInfo &Info); + + /// Transform OCL work item builtin functions to SPIR-V builtin variables. + void transWorkItemBuiltinsToVariables(); + + /// 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 all to __spirv_Op(All|Any). Note that the types mismatch so + // some extra code is emitted to convert between the two. + void visitCallAllAny(spv::Op OC, CallInst *CI); + + /// 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 atomic_compare_exchange call. + /// In atomic_compare_exchange, the expected value parameter is a pointer. + /// However in SPIR-V it is a value. The transformation adds a load + /// instruction, result of which is passed to atomic_compare_exchange as + /// argument. + /// The transformation adds a store instruction after the call, to update the + /// value in expected with the value pointed to by object. Though, it is not + /// necessary in case they are equal, this approach makes result code simpler. + /// Also ICmp instruction is added, because the call must return result of + /// comparison. + /// \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 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 OCL builtin function to SPIR-V builtin function. + /// Assuming there is a simple name mapping without argument changes. + /// Should be called at last. + void visitCallBuiltinSimple(CallInst *CI, StringRef MangledName, + const std::string &DemangledName); + + /// Transform get_image_{width|height|depth|dim}. + /// get_image_xxx(...) => + /// dimension = __spirv_ImageQuerySizeLod_R{ReturnType}(...); + /// return dimension.{x|y|z}; + void visitCallGetImageSize(CallInst *CI, StringRef MangledName, + const std::string &DemangledName); + + /// Transform {work|sub}_group_x => + /// __spirv_{OpName} + /// + /// Special handling of work_group_broadcast. + /// work_group_broadcast(a, x, y, z) + /// => + /// __spirv_GroupBroadcast(a, vec3(x, y, z)) + + void visitCallGroupBuiltin(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 OCL pipe builtin function to SPIR-V pipe builtin function. + void visitCallPipeBuiltin(CallInst *CI, StringRef MangledName, + const std::string &DemangledName); + + /// Transform read_image with sampler arguments. + /// read_image(image, sampler, ...) => + /// sampled_image = __spirv_SampledImage(image, sampler); + /// return __spirv_ImageSampleExplicitLod_R{ReturnType}(sampled_image, ...); + void visitCallReadImageWithSampler(CallInst *CI, StringRef MangledName, + const std::string &DemangledName); + + /// Transform read_image with msaa image arguments. + /// Sample argument must be acoded as Image Operand. + void visitCallReadImageMSAA(CallInst *CI, StringRef MangledName, + const std::string &DemangledName); + + /// Transform {read|write}_image without sampler arguments. + void visitCallReadWriteImage(CallInst *CI, StringRef MangledName, + const std::string &DemangledName); + + /// Transform to_{global|local|private}. + /// + /// T* a = ...; + /// addr T* b = to_addr(a); + /// => + /// i8* x = cast<i8*>(a); + /// addr i8* y = __spirv_GenericCastToPtr_ToAddr(x); + /// addr T* b = cast<addr T*>(y); + void visitCallToAddr(CallInst *CI, StringRef MangledName, + const std::string &DemangledName); + + /// Transform return type of relatinal built-in functions like isnan, isfinite + /// to boolean values. + void visitCallRelational(CallInst *CI, const std::string &DemangledName); + + /// Transform vector load/store functions to SPIR-V extended builtin + /// functions + /// {vload|vstore{a}}{_half}{n}{_rte|_rtz|_rtp|_rtn} => + /// __spirv_ocl_{ExtendedInstructionOpCodeName}__R{ReturnType} + void visitCallVecLoadStore(CallInst *CI, StringRef MangledName, + const std::string &DemangledName); + + /// Transforms get_mem_fence built-in to SPIR-V function and aligns result values with SPIR 1.2. + /// get_mem_fence(ptr) => __spirv_GenericPtrMemSemantics + /// GenericPtrMemSemantics valid values are 0x100, 0x200 and 0x300, where is + /// SPIR 1.2 defines them as 0x1, 0x2 and 0x3, so this function adjusts + /// GenericPtrMemSemantics results to SPIR 1.2 values. + void visitCallGetFence(CallInst *CI, StringRef MangledName, const std::string& DemangledName); + + /// Transforms OpDot instructions with a scalar type to a fmul instruction + void visitCallDot(CallInst *CI); + + /// Fixes for built-in functions with vector+scalar arguments that are + /// translated to the SPIR-V instructions where all arguments must have the + /// same type. + void visitCallScalToVec(CallInst *CI, StringRef MangledName, + const std::string &DemangledName); + + /// Transform get_image_channel_{order|data_type} built-in functions to + /// __spirv_ocl_{ImageQueryOrder|ImageQueryFormat} + void visitCallGetImageChannel(CallInst *CI, StringRef MangledName, + const std::string &DemangledName, + unsigned int Offset); + + /// For cl_intel_subgroups block read built-ins: + void visitSubgroupBlockReadINTEL(CallInst *CI, StringRef MangledName, + const std::string &DemangledName); + + /// For cl_intel_subgroups block write built-ins: + void visitSubgroupBlockWriteINTEL(CallInst *CI, StringRef MangledName, + const std::string &DemangledName); + + void visitDbgInfoIntrinsic(DbgInfoIntrinsic &I){ + I.dropAllReferences(); + I.eraseFromParent(); + } + static char ID; +private: + Module *M; + LLVMContext *Ctx; + unsigned CLVer; /// OpenCL version as major*10+minor + std::set<Value *> ValuesToDelete; + + ConstantInt *addInt32(int I) { + return getInt32(M, I); + } + ConstantInt *addSizet(uint64_t I) { + return getSizet(M, I); + } + + /// Get vector width from OpenCL vload* function name. + SPIRVWord getVecLoadWidth(const std::string& DemangledName) { + SPIRVWord Width = 0; + if (DemangledName == "vloada_half") + Width = 1; + else { + unsigned Loc = 5; + if (DemangledName.find("vload_half") == 0) + Loc = 10; + else if (DemangledName.find("vloada_half") == 0) + Loc = 11; + + std::stringstream SS(DemangledName.substr(Loc)); + SS >> Width; + } + return Width; + } + + /// Transform OpenCL vload/vstore function name. + void transVecLoadStoreName(std::string& DemangledName, + const std::string &Stem, bool AlwaysN) { + auto HalfStem = Stem + "_half"; + auto HalfStemR = HalfStem + "_r"; + if (!AlwaysN && DemangledName == HalfStem) + return; + if (!AlwaysN && DemangledName.find(HalfStemR) == 0) { + DemangledName = HalfStemR; + return; + } + if (DemangledName.find(HalfStem) == 0) { + auto OldName = DemangledName; + DemangledName = HalfStem + "n"; + if (OldName.find("_r") != std::string::npos) + DemangledName += "_r"; + return; + } + if (DemangledName.find(Stem) == 0) { + DemangledName = Stem + "n"; + return; + } + } + +}; + +char OCL20ToSPIRV::ID = 0; + +bool +OCL20ToSPIRV::runOnModule(Module& Module) { + M = &Module; + Ctx = &M->getContext(); + auto Src = getSPIRVSource(&Module); + if (std::get<0>(Src) != spv::SourceLanguageOpenCL_C) + return false; + + CLVer = std::get<1>(Src); + if (CLVer > kOCLVer::CL20) + return false; + + DEBUG(dbgs() << "Enter OCL20ToSPIRV:\n"); + + transWorkItemBuiltinsToVariables(); + + visit(*M); + + for (auto &I:ValuesToDelete) + if (auto Inst = dyn_cast<Instruction>(I)) + Inst->eraseFromParent(); + for (auto &I:ValuesToDelete) + if (auto GV = dyn_cast<GlobalValue>(I)) + GV->eraseFromParent(); + + DEBUG(dbgs() << "After OCL20ToSPIRV:\n" << *M); + + std::string Err; + raw_string_ostream ErrorOS(Err); + if (verifyModule(*M, &ErrorOS)){ + DEBUG(errs() << "Fails to verify module: " << ErrorOS.str()); + } + return true; +} + +// The order of handling OCL builtin functions is important. +// Workgroup functions need to be handled before pipe functions since +// there are functions fall into both categories. +void +OCL20ToSPIRV::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, &DemangledName)) + return; + + DEBUG(dbgs() << "DemangledName: " << DemangledName << '\n'); + if (DemangledName.find(kOCLBuiltinName::NDRangePrefix) == 0) { + visitCallNDRange(&CI, DemangledName); + return; + } + if (DemangledName == kOCLBuiltinName::All) { + visitCallAllAny(OpAll, &CI); + return; + } + if (DemangledName == kOCLBuiltinName::Any) { + visitCallAllAny(OpAny, &CI); + return; + } + if (DemangledName.find(kOCLBuiltinName::AsyncWorkGroupCopy) == 0 || + DemangledName.find(kOCLBuiltinName::AsyncWorkGroupStridedCopy) == 0) { + visitCallAsyncWorkGroupCopy(&CI, DemangledName); + return; + } + 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::AtomicCmpXchgWeak || + DemangledName == kOCLBuiltinName::AtomicCmpXchgStrong || + DemangledName == kOCLBuiltinName::AtomicCmpXchgWeakExplicit || + DemangledName == kOCLBuiltinName::AtomicCmpXchgStrongExplicit) { + assert(CLVer == kOCLVer::CL20 && "Wrong version of OpenCL"); + PCI = visitCallAtomicCmpXchg(PCI, DemangledName); + } + visitCallAtomicLegacy(PCI, MangledName, DemangledName); + visitCallAtomicCpp11(PCI, MangledName, DemangledName); + return; + } + if (DemangledName.find(kOCLBuiltinName::ConvertPrefix) == 0) { + visitCallConvert(&CI, MangledName, DemangledName); + return; + } + if (DemangledName == kOCLBuiltinName::GetImageWidth || + DemangledName == kOCLBuiltinName::GetImageHeight || + DemangledName == kOCLBuiltinName::GetImageDepth || + DemangledName == kOCLBuiltinName::GetImageDim || + DemangledName == kOCLBuiltinName::GetImageArraySize) { + visitCallGetImageSize(&CI, MangledName, DemangledName); + return; + } + if ((DemangledName.find(kOCLBuiltinName::WorkGroupPrefix) == 0 && + DemangledName != kOCLBuiltinName::WorkGroupBarrier) || + DemangledName == kOCLBuiltinName::WaitGroupEvent || + (DemangledName.find(kOCLBuiltinName::SubGroupPrefix) == 0 && + DemangledName != kOCLBuiltinName::SubGroupBarrier)) { + visitCallGroupBuiltin(&CI, MangledName, DemangledName); + return; + } + if (DemangledName.find(kOCLBuiltinName::Pipe) != std::string::npos) { + visitCallPipeBuiltin(&CI, MangledName, DemangledName); + return; + } + if (DemangledName == kOCLBuiltinName::MemFence) { + visitCallMemFence(&CI); + return; + } + if (DemangledName.find(kOCLBuiltinName::ReadImage) == 0) { + if (MangledName.find(kMangledName::Sampler) != StringRef::npos) { + visitCallReadImageWithSampler(&CI, MangledName, DemangledName); + return; + } + if (MangledName.find("msaa") != StringRef::npos) { + visitCallReadImageMSAA(&CI, MangledName, DemangledName); + return; + } + } + if (DemangledName.find(kOCLBuiltinName::ReadImage) == 0 || + DemangledName.find(kOCLBuiltinName::WriteImage) == 0) { + visitCallReadWriteImage(&CI, MangledName, DemangledName); + return; + } + if (DemangledName == kOCLBuiltinName::ToGlobal || + DemangledName == kOCLBuiltinName::ToLocal || + DemangledName == kOCLBuiltinName::ToPrivate) { + visitCallToAddr(&CI, MangledName, DemangledName); + return; + } + if (DemangledName.find(kOCLBuiltinName::VLoadPrefix) == 0 || + DemangledName.find(kOCLBuiltinName::VStorePrefix) == 0) { + visitCallVecLoadStore(&CI, MangledName, DemangledName); + return; + } + if (DemangledName == kOCLBuiltinName::IsFinite || + DemangledName == kOCLBuiltinName::IsInf || + DemangledName == kOCLBuiltinName::IsNan || + DemangledName == kOCLBuiltinName::IsNormal || + DemangledName == kOCLBuiltinName::Signbit) { + visitCallRelational(&CI, DemangledName); + return; + } + if (DemangledName == kOCLBuiltinName::WorkGroupBarrier || + DemangledName == kOCLBuiltinName::Barrier) { + visitCallBarrier(&CI); + return; + } + if (DemangledName == kOCLBuiltinName::GetFence) { + visitCallGetFence(&CI, MangledName, DemangledName); + return; + } + if (DemangledName == kOCLBuiltinName::Dot && + !(CI.getOperand(0)->getType()->isVectorTy())) { + visitCallDot(&CI); + return; + } + if (DemangledName == kOCLBuiltinName::FMin || + DemangledName == kOCLBuiltinName::FMax || + DemangledName == kOCLBuiltinName::Min || + DemangledName == kOCLBuiltinName::Max || + DemangledName == kOCLBuiltinName::Step || + DemangledName == kOCLBuiltinName::SmoothStep || + DemangledName == kOCLBuiltinName::Clamp || + DemangledName == kOCLBuiltinName::Mix) { + visitCallScalToVec(&CI, MangledName, DemangledName); + return; + } + if (DemangledName == kOCLBuiltinName::GetImageChannelDataType) { + visitCallGetImageChannel(&CI, MangledName, DemangledName, + OCLImageChannelDataTypeOffset); + return; + } + if (DemangledName == kOCLBuiltinName::GetImageChannelOrder) { + visitCallGetImageChannel(&CI, MangledName, DemangledName, + OCLImageChannelOrderOffset); + return; + } + if (DemangledName.find(kOCLBuiltinName::SubgroupBlockReadINTELPrefix) == 0) { + visitSubgroupBlockReadINTEL(&CI, MangledName, DemangledName); + return; + } + if (DemangledName.find(kOCLBuiltinName::SubgroupBlockWriteINTELPrefix) == 0) { + visitSubgroupBlockWriteINTEL(&CI, MangledName, DemangledName); + return; + } + visitCallBuiltinSimple(&CI, MangledName, DemangledName); +} + +void +OCL20ToSPIRV::visitCallNDRange(CallInst *CI, + const std::string &DemangledName) { + assert(DemangledName.find(kOCLBuiltinName::NDRangePrefix) == 0); + std::string lenStr = DemangledName.substr(8, 1); + auto Len = atoi(lenStr.c_str()); + assert (Len >= 1 && Len <= 3); + // SPIR-V ndrange structure requires 3 members in the following order: + // global work offset + // global work size + // local work size + // The arguments need to add missing members. + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args){ + for (size_t I = 1, E = Args.size(); I != E; ++I) + Args[I] = getScalarOrArray(Args[I], Len, CI); + switch (Args.size()) { + case 2: { + // Has global work size. + auto T = Args[1]->getType(); + auto C = getScalarOrArrayConstantInt(CI, T, Len, 0); + Args.push_back(C); + Args.push_back(C); + } + break; + case 3: { + // Has global and local work size. + auto T = Args[1]->getType(); + Args.push_back(getScalarOrArrayConstantInt(CI, T, Len, 0)); + } + break; + case 4: { + // Move offset arg to the end + auto OffsetPos = Args.begin() + 1; + Value* OffsetVal = *OffsetPos; + Args.erase(OffsetPos); + Args.push_back(OffsetVal); + } + break; + default: + assert(0 && "Invalid number of arguments"); + } + // Translate ndrange_ND into differently named SPIR-V decorated functions because + // they have array arugments of different dimension which mangled the same way. + return getSPIRVFuncName(OpBuildNDRange, "_" + lenStr + "D"); + }, &Attrs); +} + +void +OCL20ToSPIRV::visitCallAsyncWorkGroupCopy(CallInst* CI, + const std::string &DemangledName) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args){ + if (DemangledName == OCLUtil::kOCLBuiltinName::AsyncWorkGroupCopy) { + Args.insert(Args.begin()+3, addSizet(1)); + } + Args.insert(Args.begin(), addInt32(ScopeWorkgroup)); + return getSPIRVFuncName(OpGroupAsyncCopy); + }, &Attrs); +} + +CallInst * +OCL20ToSPIRV::visitCallAtomicCmpXchg(CallInst* CI, + const std::string& DemangledName) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + Value *Expected = nullptr; + CallInst *NewCI = nullptr; + mutateCallInstOCL(M, CI, [&](CallInst * CI, std::vector<Value *> &Args, + Type *&RetTy){ + Expected = Args[1]; // temporary save second argument. + Args[1] = new LoadInst(Args[1], "exp", false, CI); + RetTy = Args[2]->getType(); + assert(Args[0]->getType()->getPointerElementType()->isIntegerTy() && + Args[1]->getType()->isIntegerTy() && Args[2]->getType()->isIntegerTy() && + "In SPIR-V 1.0 arguments of OpAtomicCompareExchange must be " + "an integer type scalars"); + return kOCLBuiltinName::AtomicCmpXchgStrong; + }, + [&](CallInst *NCI)->Instruction * { + NewCI = NCI; + Instruction* Store = new StoreInst(NCI, Expected, NCI->getNextNode()); + return new ICmpInst(Store->getNextNode(), CmpInst::ICMP_EQ, NCI, + NCI->getArgOperand(1)); + }, + &Attrs); + return NewCI; +} + +void +OCL20ToSPIRV::visitCallAtomicInit(CallInst* CI) { + auto ST = new StoreInst(CI->getArgOperand(1), CI->getArgOperand(0), CI); + ST->takeName(CI); + CI->dropAllReferences(); + CI->eraseFromParent(); +} + +void +OCL20ToSPIRV::visitCallAllAny(spv::Op OC, CallInst* CI) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + + auto Args = getArguments(CI); + assert(Args.size() == 1); + + auto *ArgTy = Args[0]->getType(); + auto Zero = Constant::getNullValue(Args[0]->getType()); + + auto *Cmp = CmpInst::Create(CmpInst::ICmp, CmpInst::ICMP_SLT, Args[0], Zero, + "cast", CI); + + if (!isa<VectorType>(ArgTy)) { + auto *Cast = CastInst::CreateZExtOrBitCast(Cmp, Type::getInt32Ty(*Ctx), + "", Cmp->getNextNode()); + CI->replaceAllUsesWith(Cast); + CI->eraseFromParent(); + } else { + mutateCallInstSPIRV( + M, CI, + [&](CallInst *, std::vector<Value *> &Args, Type *&Ret) { + Args[0] = Cmp; + Ret = Type::getInt1Ty(*Ctx); + + return getSPIRVFuncName(OC); + }, + [&](CallInst *CI) -> Instruction * { + return CastInst::CreateZExtOrBitCast(CI, Type::getInt32Ty(*Ctx), "", + CI->getNextNode()); + }, + &Attrs); + } +} + +void +OCL20ToSPIRV::visitCallAtomicWorkItemFence(CallInst* CI) { + transMemoryBarrier(CI, getAtomicWorkItemFenceLiterals(CI)); +} + +void +OCL20ToSPIRV::visitCallMemFence(CallInst* CI) { + transMemoryBarrier(CI, std::make_tuple( + cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue(), + OCLMO_relaxed, + OCLMS_work_group)); +} + +void OCL20ToSPIRV::transMemoryBarrier(CallInst* CI, + AtomicWorkItemFenceLiterals Lit) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args){ + Args.resize(2); + Args[0] = addInt32(map<Scope>(std::get<2>(Lit))); + Args[1] = addInt32(mapOCLMemSemanticToSPIRV(std::get<0>(Lit), + std::get<1>(Lit))); + return getSPIRVFuncName(OpMemoryBarrier); + }, &Attrs); +} + +void +OCL20ToSPIRV::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 +OCL20ToSPIRV::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 +OCL20ToSPIRV::transAtomicBuiltin(CallInst* CI, + OCLBuiltinTransInfo& Info) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + mutateCallInstSPIRV(M, CI, [=](CallInst * CI, std::vector<Value *> &Args){ + Info.PostProc(Args); + // Order of args in OCL20: + // object, 0-2 other args, 1-2 order, scope + const size_t NumOrder = getAtomicBuiltinNumMemoryOrderArgs(Info.UniqName); + const size_t ArgsCount = Args.size(); + const size_t ScopeIdx = ArgsCount - 1; + const size_t OrderIdx = ScopeIdx - NumOrder; + Args[ScopeIdx] = mapUInt(M, cast<ConstantInt>(Args[ScopeIdx]), + [](unsigned I){ + return map<Scope>(static_cast<OCLScopeKind>(I)); + }); + for (size_t I = 0; I < NumOrder; ++I) + Args[OrderIdx + I] = mapUInt(M, cast<ConstantInt>(Args[OrderIdx + I]), + [](unsigned Ord) { + return mapOCLMemSemanticToSPIRV(0, static_cast<OCLMemOrderKind>(Ord)); + }); + // Order of args in SPIR-V: + // object, scope, 1-2 order, 0-2 other args + std::swap(Args[1], Args[ScopeIdx]); + if(OrderIdx > 2) { + // For atomic_compare_exchange the swap above puts Comparator/Expected + // argument just where it should be, so don't move the last argument then. + int offset = Info.UniqName.find("atomic_compare_exchange") == 0 ? 1 : 0; + std::rotate(Args.begin() + 2, Args.begin() + OrderIdx, + Args.end() - offset); + } + return getSPIRVFuncName(OCLSPIRVBuiltinMap::map(Info.UniqName)); + }, &Attrs); +} + +void +OCL20ToSPIRV::visitCallBarrier(CallInst* CI) { + auto Lit = getBarrierLiterals(CI); + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args){ + Args.resize(3); + Args[0] = addInt32(map<Scope>(std::get<2>(Lit))); + Args[1] = addInt32(map<Scope>(std::get<1>(Lit))); + Args[2] = addInt32(mapOCLMemFenceFlagToSPIRV(std::get<0>(Lit))); + return getSPIRVFuncName(OpControlBarrier); + }, &Attrs); +} + +void OCL20ToSPIRV::visitCallConvert(CallInst* CI, + StringRef MangledName, const std::string& DemangledName) { + if (eraseUselessConvert(CI, MangledName, DemangledName)) + return; + Op OC = OpNop; + auto TargetTy = CI->getType(); + auto SrcTy = CI->getArgOperand(0)->getType(); + if (isa<VectorType>(TargetTy)) + TargetTy = TargetTy->getVectorElementType(); + if (isa<VectorType>(SrcTy)) + SrcTy = SrcTy->getVectorElementType(); + auto IsTargetInt = isa<IntegerType>(TargetTy); + + std::string TargetTyName = DemangledName.substr( + strlen(kOCLBuiltinName::ConvertPrefix)); + auto FirstUnderscoreLoc = TargetTyName.find('_'); + if (FirstUnderscoreLoc != std::string::npos) + TargetTyName = TargetTyName.substr(0, FirstUnderscoreLoc); + TargetTyName = std::string("_R") + TargetTyName; + + std::string Sat = DemangledName.find("_sat") != std::string::npos ? + "_sat" : ""; + auto TargetSigned = DemangledName[8] != 'u'; + if (isa<IntegerType>(SrcTy)) { + bool Signed = isLastFuncParamSigned(MangledName); + if (IsTargetInt) { + if (!Sat.empty() && TargetSigned != Signed) { + OC = Signed ? OpSatConvertSToU : OpSatConvertUToS; + Sat = ""; + } else + OC = Signed ? OpSConvert : OpUConvert; + } else + OC = Signed ? OpConvertSToF : OpConvertUToF; + } else { + if (IsTargetInt) { + OC = TargetSigned ? OpConvertFToS : OpConvertFToU; + } else + OC = OpFConvert; + } + auto Loc = DemangledName.find("_rt"); + std::string Rounding; + if (Loc != std::string::npos && + !(isa<IntegerType>(SrcTy) && IsTargetInt)) { + Rounding = DemangledName.substr(Loc, 4); + } + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args){ + return getSPIRVFuncName(OC, TargetTyName + Sat + Rounding); + }, &Attrs); +} + +void OCL20ToSPIRV::visitCallGroupBuiltin(CallInst* CI, + StringRef MangledName, const std::string& OrigDemangledName) { + auto F = CI->getCalledFunction(); + std::vector<int> PreOps; + std::string DemangledName = OrigDemangledName; + + if (DemangledName == kOCLBuiltinName::WorkGroupBarrier) + return; + if (DemangledName == kOCLBuiltinName::WaitGroupEvent) { + PreOps.push_back(ScopeWorkgroup); + } else if (DemangledName.find(kOCLBuiltinName::WorkGroupPrefix) == 0) { + DemangledName.erase(0, strlen(kOCLBuiltinName::WorkPrefix)); + PreOps.push_back(ScopeWorkgroup); + } else if (DemangledName.find(kOCLBuiltinName::SubGroupPrefix) == 0) { + DemangledName.erase(0, strlen(kOCLBuiltinName::SubPrefix)); + PreOps.push_back(ScopeSubgroup); + } else + return; + + if (DemangledName != kOCLBuiltinName::WaitGroupEvent) { + StringRef GroupOp = DemangledName; + GroupOp = GroupOp.drop_front(strlen(kSPIRVName::GroupPrefix)); + SPIRSPIRVGroupOperationMap::foreach_conditional([&](const std::string &S, + SPIRVGroupOperationKind G){ + if (!GroupOp.startswith(S)) + return true; // continue + PreOps.push_back(G); + StringRef Op = GroupOp.drop_front(S.size() + 1); + assert(!Op.empty() && "Invalid OpenCL group builtin function"); + char OpTyC = 0; + auto NeedSign = Op == "max" || Op == "min"; + auto OpTy = F->getReturnType(); + if (OpTy->isFloatingPointTy()) + OpTyC = 'f'; + else if (OpTy->isIntegerTy()) { + if (!NeedSign) + OpTyC = 'i'; + else { + if (isLastFuncParamSigned(F->getName())) + OpTyC = 's'; + else + OpTyC = 'u'; + } + } else + llvm_unreachable("Invalid OpenCL group builtin argument type"); + + DemangledName = std::string(kSPIRVName::GroupPrefix) + OpTyC + Op.str(); + return false; // break out of loop + }); + } + + bool IsGroupAllAny = (DemangledName.find("_all") != std::string::npos || + DemangledName.find("_any") != std::string::npos); + + auto Consts = getInt32(M, PreOps); + OCLBuiltinTransInfo Info; + if (IsGroupAllAny) + Info.RetTy = Type::getInt1Ty(*Ctx); + Info.UniqName = DemangledName; + Info.PostProc = [=](std::vector<Value *> &Ops) { + if (IsGroupAllAny) { + IRBuilder<> IRB(CI); + Ops[0] = + IRB.CreateICmpNE(Ops[0], ConstantInt::get(Type::getInt32Ty(*Ctx), 0)); + } + size_t E = Ops.size(); + if (DemangledName == "group_broadcast" && E > 2) { + assert(E == 3 || E == 4); + makeVector(CI, Ops, std::make_pair(Ops.begin() + 1, Ops.end())); + } + Ops.insert(Ops.begin(), Consts.begin(), Consts.end()); + }; + transBuiltin(CI, Info); +} + +void +OCL20ToSPIRV::transBuiltin(CallInst* CI, + OCLBuiltinTransInfo& Info) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + Op OC = OpNop; + unsigned ExtOp = ~0U; + if (StringRef(Info.UniqName).startswith(kSPIRVName::Prefix)) + return; + if (OCLSPIRVBuiltinMap::find(Info.UniqName, &OC)) + Info.UniqName = getSPIRVFuncName(OC); + else if ((ExtOp = getExtOp(Info.MangledName, Info.UniqName)) != ~0U) + Info.UniqName = getSPIRVExtFuncName(SPIRVEIS_OpenCL, ExtOp); + else + return; + if (!Info.RetTy) + mutateCallInstSPIRV(M, CI, + [=](CallInst *, std::vector<Value *> &Args) { + Info.PostProc(Args); + return Info.UniqName + Info.Postfix; + }, + &Attrs); + else + mutateCallInstSPIRV( + M, CI, + [=](CallInst *, std::vector<Value *> &Args, Type *&RetTy) { + Info.PostProc(Args); + RetTy = Info.RetTy; + return Info.UniqName + Info.Postfix; + }, + [=](CallInst *NewCI) -> Instruction * { + if (NewCI->getType()->isIntegerTy() && CI->getType()->isIntegerTy()) + return CastInst::CreateIntegerCast(NewCI, CI->getType(), + Info.isRetSigned, "", CI); + else + return CastInst::CreatePointerBitCastOrAddrSpaceCast( + NewCI, CI->getType(), "", CI); + }, + &Attrs); +} + +void +OCL20ToSPIRV::visitCallPipeBuiltin(CallInst* CI, + StringRef MangledName, const std::string& DemangledName) { + std::string NewName = DemangledName; + // Transform OpenCL read_pipe/write_pipe builtin function names + // with reserve_id argument to reserved_read_pipe/reserved_write_pipe. + if ((DemangledName.find(kOCLBuiltinName::ReadPipe) == 0 || + DemangledName.find(kOCLBuiltinName::WritePipe) == 0) + && CI->getNumArgOperands() > 4) + NewName = std::string(kSPIRVName::ReservedPrefix) + DemangledName; + OCLBuiltinTransInfo Info; + Info.UniqName = NewName; + transBuiltin(CI, Info); +} + +void OCL20ToSPIRV::visitCallReadImageMSAA(CallInst *CI, StringRef MangledName, + const std::string &DemangledName) { + assert(MangledName.find("msaa") != StringRef::npos); + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + mutateCallInstSPIRV( + M, CI, + [=](CallInst *, std::vector<Value *> &Args) { + Args.insert(Args.begin() + 2, getInt32(M, ImageOperandsSampleMask)); + return getSPIRVFuncName(OpImageRead, + std::string(kSPIRVPostfix::ExtDivider) + + getPostfixForReturnType(CI)); + }, + &Attrs); +} + +void OCL20ToSPIRV::visitCallReadImageWithSampler( + CallInst *CI, StringRef MangledName, const std::string &DemangledName) { + assert (MangledName.find(kMangledName::Sampler) != StringRef::npos); + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + bool isRetScalar = !CI->getType()->isVectorTy(); + mutateCallInstSPIRV( + M, CI, + [=](CallInst *, std::vector<Value *> &Args, Type *&Ret) { + auto ImageTy = getAnalysis<OCLTypeToSPIRV>().getAdaptedType(Args[0]); + if (isOCLImageType(ImageTy)) + ImageTy = getSPIRVImageTypeFromOCL(M, ImageTy); + auto SampledImgTy = getSPIRVTypeByChangeBaseTypeName( + M, ImageTy, kSPIRVTypeName::Image, kSPIRVTypeName::SampledImg); + Value *SampledImgArgs[] = {Args[0], Args[1]}; + auto SampledImg = addCallInstSPIRV( + M, getSPIRVFuncName(OpSampledImage), SampledImgTy, SampledImgArgs, + nullptr, CI, kSPIRVName::TempSampledImage); + + Args[0] = SampledImg; + Args.erase(Args.begin() + 1, Args.begin() + 2); + + switch (Args.size()) { + case 2: // no lod + Args.push_back(getInt32(M, ImageOperandsMask::ImageOperandsLodMask)); + Args.push_back(getFloat32(M, 0.f)); + break; + case 3: // explicit lod + Args.insert(Args.begin() + 2, + getInt32(M, ImageOperandsMask::ImageOperandsLodMask)); + break; + case 4: // gradient + Args.insert(Args.begin() + 2, + getInt32(M, ImageOperandsMask::ImageOperandsGradMask)); + break; + default: + assert(0 && "read_image* with unhandled number of args!"); + } + + // SPIR-V intruction always returns 4-element vector + if (isRetScalar) + Ret = VectorType::get(Ret, 4); + return getSPIRVFuncName(OpImageSampleExplicitLod, + std::string(kSPIRVPostfix::ExtDivider) + + getPostfixForReturnType(Ret)); + }, + [&](CallInst *CI) -> Instruction * { + if (isRetScalar) + return ExtractElementInst::Create(CI, getSizet(M, 0), "", + CI->getNextNode()); + return CI; + }, + &Attrs); +} + +void +OCL20ToSPIRV::visitCallGetImageSize(CallInst* CI, + StringRef MangledName, const std::string& DemangledName) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + StringRef TyName; + SmallVector<StringRef, 4> SubStrs; + auto IsImg = isOCLImageType(CI->getArgOperand(0)->getType(), &TyName); + (void)IsImg; + assert(IsImg); + std::string ImageTyName = TyName.str(); + if (hasAccessQualifiedName(TyName)) + ImageTyName.erase(ImageTyName.size() - 5, 3); + auto Desc = map<SPIRVTypeImageDescriptor>(ImageTyName); + unsigned Dim = getImageDimension(Desc.Dim) + Desc.Arrayed; + assert(Dim > 0 && "Invalid image dimension."); + mutateCallInstSPIRV(M, CI, + [&](CallInst *, std::vector<Value *> &Args, Type *&Ret){ + assert(Args.size() == 1); + Ret = CI->getType()->isIntegerTy(64) ? Type::getInt64Ty(*Ctx) + : Type::getInt32Ty(*Ctx); + if (Dim > 1) + Ret = VectorType::get(Ret, Dim); + if (Desc.Dim == DimBuffer) + return getSPIRVFuncName(OpImageQuerySize, CI->getType()); + else { + Args.push_back(getInt32(M, 0)); + return getSPIRVFuncName(OpImageQuerySizeLod, CI->getType()); + } + }, + [&](CallInst *NCI)->Instruction * { + if (Dim == 1) + return NCI; + if (DemangledName == kOCLBuiltinName::GetImageDim) { + if (Desc.Dim == Dim3D) { + auto ZeroVec = ConstantVector::getSplat(3, + Constant::getNullValue(NCI->getType()->getVectorElementType())); + Constant *Index[] = {getInt32(M, 0), getInt32(M, 1), + getInt32(M, 2), getInt32(M, 3)}; + return new ShuffleVectorInst(NCI, ZeroVec, + ConstantVector::get(Index), "", CI); + + } else if (Desc.Dim == Dim2D && Desc.Arrayed) { + Constant *Index[] = {getInt32(M, 0), getInt32(M, 1)}; + Constant *mask = ConstantVector::get(Index); + return new ShuffleVectorInst(NCI, UndefValue::get(NCI->getType()), + mask, NCI->getName(), CI); + } + return NCI; + } + unsigned I = StringSwitch<unsigned>(DemangledName) + .Case(kOCLBuiltinName::GetImageWidth, 0) + .Case(kOCLBuiltinName::GetImageHeight, 1) + .Case(kOCLBuiltinName::GetImageDepth, 2) + .Case(kOCLBuiltinName::GetImageArraySize, Dim - 1); + return ExtractElementInst::Create(NCI, getUInt32(M, I), "", + NCI->getNextNode()); + }, + &Attrs); +} + +/// Remove trivial conversion functions +bool +OCL20ToSPIRV::eraseUselessConvert(CallInst *CI, + const std::string &MangledName, + const std::string &DemangledName) { + auto TargetTy = CI->getType(); + auto SrcTy = CI->getArgOperand(0)->getType(); + if (isa<VectorType>(TargetTy)) + TargetTy = TargetTy->getVectorElementType(); + if (isa<VectorType>(SrcTy)) + SrcTy = SrcTy->getVectorElementType(); + if (TargetTy == SrcTy) { + if (isa<IntegerType>(TargetTy) && + DemangledName.find("_sat") != std::string::npos && + isLastFuncParamSigned(MangledName) != (DemangledName[8] != 'u')) + return false; + CI->getArgOperand(0)->takeName(CI); + SPIRVDBG(dbgs() << "[regularizeOCLConvert] " << *CI << " <- " << + *CI->getArgOperand(0) << '\n'); + CI->replaceAllUsesWith(CI->getArgOperand(0)); + ValuesToDelete.insert(CI); + ValuesToDelete.insert(CI->getCalledFunction()); + return true; + } + return false; +} + +void +OCL20ToSPIRV::visitCallBuiltinSimple(CallInst* CI, + StringRef MangledName, const std::string& DemangledName) { + OCLBuiltinTransInfo Info; + Info.MangledName = MangledName.str(); + Info.UniqName = DemangledName; + transBuiltin(CI, Info); +} + +/// Translates OCL work-item builtin functions to SPIRV builtin variables. +/// Function like get_global_id(i) -> x = load GlobalInvocationId; extract x, i +/// Function like get_work_dim() -> load WorkDim +void OCL20ToSPIRV::transWorkItemBuiltinsToVariables() { + DEBUG(dbgs() << "Enter transWorkItemBuiltinsToVariables\n"); + std::vector<Function *> WorkList; + for (auto &I:*M) { + std::string DemangledName; + if (!oclIsBuiltin(I.getName(), &DemangledName)) + continue; + DEBUG(dbgs() << "Function demangled name: " << DemangledName << '\n'); + std::string BuiltinVarName; + SPIRVBuiltinVariableKind BVKind; + if (!SPIRSPIRVBuiltinVariableMap::find(DemangledName, &BVKind)) + continue; + BuiltinVarName = std::string(kSPIRVName::Prefix) + + SPIRVBuiltInNameMap::map(BVKind); + DEBUG(dbgs() << "builtin variable name: " << BuiltinVarName << '\n'); + bool IsVec = I.getFunctionType()->getNumParams() > 0; + Type *GVType = IsVec ? VectorType::get(I.getReturnType(),3) : + I.getReturnType(); + auto BV = new GlobalVariable(*M, GVType, + true, + GlobalValue::ExternalLinkage, + nullptr, BuiltinVarName, + 0, + GlobalVariable::NotThreadLocal, + SPIRAS_Constant); + std::vector<Instruction *> InstList; + for (auto UI = I.user_begin(), UE = I.user_end(); UI != UE; ++UI) { + auto CI = dyn_cast<CallInst>(*UI); + assert(CI && "invalid instruction"); + Value * NewValue = new LoadInst(BV, "", CI); + DEBUG(dbgs() << "Transform: " << *CI << " => " << *NewValue << '\n'); + if (IsVec) { + NewValue = ExtractElementInst::Create(NewValue, + CI->getArgOperand(0), + "", CI); + DEBUG(dbgs() << *NewValue << '\n'); + } + NewValue->takeName(CI); + CI->replaceAllUsesWith(NewValue); + InstList.push_back(CI); + } + for (auto &Inst:InstList) { + Inst->eraseFromParent(); + } + WorkList.push_back(&I); + } + for (auto &I:WorkList) { + I->eraseFromParent(); + } +} + +void +OCL20ToSPIRV::visitCallReadWriteImage(CallInst* CI, + StringRef MangledName, const std::string& DemangledName) { + OCLBuiltinTransInfo Info; + if (DemangledName.find(kOCLBuiltinName::ReadImage) == 0) + Info.UniqName = kOCLBuiltinName::ReadImage; + + if (DemangledName.find(kOCLBuiltinName::WriteImage) == 0) + { + Info.UniqName = kOCLBuiltinName::WriteImage; + Info.PostProc = [&](std::vector<Value*> &Args) { + if (Args.size() == 4) // write with lod + { + auto Lod = Args[2]; + Args.erase(Args.begin() + 2); + Args.push_back(getInt32(M, ImageOperandsMask::ImageOperandsLodMask)); + Args.push_back(Lod); + } + }; + } + + transBuiltin(CI, Info); +} + +void +OCL20ToSPIRV::visitCallToAddr(CallInst* CI, StringRef MangledName, + const std::string &DemangledName) { + auto AddrSpace = static_cast<SPIRAddressSpace>( + CI->getType()->getPointerAddressSpace()); + OCLBuiltinTransInfo Info; + Info.UniqName = DemangledName; + Info.Postfix = std::string(kSPIRVPostfix::Divider) + "To" + + SPIRAddrSpaceCapitalizedNameMap::map(AddrSpace); + auto StorageClass = addInt32(SPIRSPIRVAddrSpaceMap::map(AddrSpace)); + Info.RetTy = getInt8PtrTy(cast<PointerType>(CI->getType())); + Info.PostProc = [=](std::vector<Value *> &Ops){ + auto P = Ops.back(); + Ops.pop_back(); + Ops.push_back(castToInt8Ptr(P, CI)); + Ops.push_back(StorageClass); + }; + transBuiltin(CI, Info); +} + +void OCL20ToSPIRV::visitCallRelational(CallInst *CI, + const std::string &DemangledName) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + Op OC = OpNop; + OCLSPIRVBuiltinMap::find(DemangledName, &OC); + std::string SPIRVName = getSPIRVFuncName(OC); + mutateCallInstSPIRV( + M, CI, + [=](CallInst *, std::vector<Value *> &Args, Type *&Ret) { + Ret = Type::getInt1Ty(*Ctx); + if (CI->getOperand(0)->getType()->isVectorTy()) + Ret = VectorType::get( + Type::getInt1Ty(*Ctx), + CI->getOperand(0)->getType()->getVectorNumElements()); + return SPIRVName; + }, + [=](CallInst *NewCI) -> Instruction * { + Value *False = nullptr, *True = nullptr; + if (NewCI->getType()->isVectorTy()) { + Type *IntTy = Type::getInt32Ty(*Ctx); + if (cast<VectorType>(NewCI->getOperand(0)->getType()) + ->getElementType() + ->isDoubleTy()) + IntTy = Type::getInt64Ty(*Ctx); + if (cast<VectorType>(NewCI->getOperand(0)->getType()) + ->getElementType() + ->isHalfTy()) + IntTy = Type::getInt16Ty(*Ctx); + Type *VTy = VectorType::get(IntTy, + NewCI->getType()->getVectorNumElements()); + False = Constant::getNullValue(VTy); + True = Constant::getAllOnesValue(VTy); + } else { + False = getInt32(M, 0); + True = getInt32(M, 1); + } + return SelectInst::Create(NewCI, True, False, "", NewCI->getNextNode()); + }, + &Attrs); +} + +void +OCL20ToSPIRV::visitCallVecLoadStore(CallInst* CI, + StringRef MangledName, const std::string& OrigDemangledName) { + std::vector<int> PreOps; + std::string DemangledName = OrigDemangledName; + if (DemangledName.find(kOCLBuiltinName::VLoadPrefix) == 0 && + DemangledName != kOCLBuiltinName::VLoadHalf) { + SPIRVWord Width = getVecLoadWidth(DemangledName); + SPIRVDBG(spvdbgs() << "[visitCallVecLoadStore] DemangledName: " << + DemangledName << " Width: " << Width << '\n'); + PreOps.push_back(Width); + } else if (DemangledName.find(kOCLBuiltinName::RoundingPrefix) + != std::string::npos) { + auto R = SPIRSPIRVFPRoundingModeMap::map(DemangledName.substr( + DemangledName.find(kOCLBuiltinName::RoundingPrefix) + 1, 3)); + PreOps.push_back(R); + } + + if (DemangledName.find(kOCLBuiltinName::VLoadAPrefix) == 0) + transVecLoadStoreName(DemangledName, kOCLBuiltinName::VLoadAPrefix, true); + else + transVecLoadStoreName(DemangledName, kOCLBuiltinName::VLoadPrefix, false); + + if (DemangledName.find(kOCLBuiltinName::VStoreAPrefix) == 0) + transVecLoadStoreName(DemangledName, kOCLBuiltinName::VStoreAPrefix, true); + else + transVecLoadStoreName(DemangledName, kOCLBuiltinName::VStorePrefix, false); + + + auto Consts = getInt32(M, PreOps); + OCLBuiltinTransInfo Info; + Info.MangledName = MangledName; + Info.UniqName = DemangledName; + if (DemangledName.find(kOCLBuiltinName::VLoadPrefix) == 0) + Info.Postfix = std::string(kSPIRVPostfix::ExtDivider) + + getPostfixForReturnType(CI); + Info.PostProc = [=](std::vector<Value *> &Ops){ + Ops.insert(Ops.end(), Consts.begin(), Consts.end()); + }; + transBuiltin(CI, Info); +} + +void OCL20ToSPIRV::visitCallGetFence(CallInst *CI, StringRef MangledName, + const std::string &DemangledName) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + Op OC = OpNop; + OCLSPIRVBuiltinMap::find(DemangledName, &OC); + std::string SPIRVName = getSPIRVFuncName(OC); + mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args, + Type *&Ret) { return SPIRVName; }, + [=](CallInst *NewCI) -> Instruction * { + return BinaryOperator::CreateLShr(NewCI, getInt32(M, 8), "", CI); + }, + &Attrs); +} + +void OCL20ToSPIRV::visitCallDot(CallInst *CI) { + IRBuilder<> Builder(CI); + Value *FMulVal = Builder.CreateFMul(CI->getOperand(0), CI->getOperand(1)); + CI->replaceAllUsesWith(FMulVal); + CI->eraseFromParent(); +} + +void OCL20ToSPIRV::visitCallScalToVec(CallInst *CI, StringRef MangledName, + const std::string &DemangledName) { + // Check if all arguments have the same type - it's simple case. + auto Uniform = true; + auto IsArg0Vector = isa<VectorType>(CI->getOperand(0)->getType()); + for (unsigned I = 1, E = CI->getNumArgOperands(); Uniform && (I != E); ++I) { + Uniform = isa<VectorType>(CI->getOperand(I)->getType()) == IsArg0Vector; + } + if (Uniform) { + visitCallBuiltinSimple(CI, MangledName, DemangledName); + return; + } + + std::vector<unsigned int> VecPos; + std::vector<unsigned int> ScalarPos; + if (DemangledName == kOCLBuiltinName::FMin || + DemangledName == kOCLBuiltinName::FMax || + DemangledName == kOCLBuiltinName::Min || + DemangledName == kOCLBuiltinName::Max) { + VecPos.push_back(0); + ScalarPos.push_back(1); + } else if (DemangledName == kOCLBuiltinName::Clamp) { + VecPos.push_back(0); + ScalarPos.push_back(1); + ScalarPos.push_back(2); + } else if (DemangledName == kOCLBuiltinName::Mix) { + VecPos.push_back(0); + VecPos.push_back(1); + ScalarPos.push_back(2); + } else if (DemangledName == kOCLBuiltinName::Step) { + VecPos.push_back(1); + ScalarPos.push_back(0); + } else if (DemangledName == kOCLBuiltinName::SmoothStep) { + VecPos.push_back(2); + ScalarPos.push_back(0); + ScalarPos.push_back(1); + } + + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + mutateCallInstSPIRV( + M, CI, + [=](CallInst *, std::vector<Value *> &Args) { + Args.resize(VecPos.size() + ScalarPos.size()); + for (auto I : VecPos) { + Args[I] = CI->getOperand(I); + } + auto VecArgWidth = + CI->getOperand(VecPos[0])->getType()->getVectorNumElements(); + for (auto I : ScalarPos) { + Instruction *Inst = InsertElementInst::Create( + UndefValue::get(CI->getOperand(VecPos[0])->getType()), + CI->getOperand(I), getInt32(M, 0), "", CI); + Value *NewVec = new ShuffleVectorInst( + Inst, UndefValue::get(CI->getOperand(VecPos[0])->getType()), + ConstantVector::getSplat(VecArgWidth, getInt32(M, 0)), "", CI); + + Args[I] = NewVec; + } + return getSPIRVExtFuncName(SPIRVEIS_OpenCL, + getExtOp(MangledName, DemangledName)); + }, + &Attrs); +} + +void OCL20ToSPIRV::visitCallGetImageChannel(CallInst *CI, StringRef MangledName, + const std::string &DemangledName, + unsigned int Offset) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + Op OC = OpNop; + OCLSPIRVBuiltinMap::find(DemangledName, &OC); + std::string SPIRVName = getSPIRVFuncName(OC); + mutateCallInstSPIRV(M, CI, [=](CallInst *, std::vector<Value *> &Args, + Type *&Ret) { return SPIRVName; }, + [=](CallInst *NewCI) -> Instruction * { + return BinaryOperator::CreateAdd( + NewCI, getInt32(M, Offset), "", CI); + }, + &Attrs); +} + +// The intel_sub_group_block_read built-ins are overloaded to support both +// buffers and images, but need to be mapped to distinct SPIR-V instructions. +// Additionally, for block reads, need to distinguish between scalar block +// reads and vector block reads. +void OCL20ToSPIRV::visitSubgroupBlockReadINTEL(CallInst *CI, StringRef MangledName, + const std::string &DemangledName) { + OCLBuiltinTransInfo Info; + if (isOCLImageType(CI->getArgOperand(0)->getType())) + Info.UniqName = getSPIRVFuncName(spv::OpSubgroupImageBlockReadINTEL); + else + Info.UniqName = getSPIRVFuncName(spv::OpSubgroupBlockReadINTEL); + if (CI->getType()->isVectorTy()) { + switch(CI->getType()->getVectorNumElements()) { + case 2: Info.Postfix = "_v2"; break; + case 4: Info.Postfix = "_v4"; break; + case 8: Info.Postfix = "_v8"; break; + default: break; + } + } + if (CI->getType()->getScalarSizeInBits() == 16) + Info.Postfix += "_us"; + else + Info.Postfix += "_ui"; + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + mutateCallInstSPIRV(M, CI, + [=](CallInst *, std::vector<Value *> &Args) { + Info.PostProc(Args); + return Info.UniqName + Info.Postfix; + }, + &Attrs); +} + +// The intel_sub_group_block_write built-ins are similarly overloaded to support +// both buffers and images but need to be mapped to distinct SPIR-V instructions. +// Since the type of data to be written is encoded in the mangled name there is +// no need to do additional work to distinguish between scalar block writes and +// vector block writes. +void OCL20ToSPIRV::visitSubgroupBlockWriteINTEL(CallInst *CI, StringRef MangledName, + const std::string &DemangledName) { + OCLBuiltinTransInfo Info; + if (isOCLImageType(CI->getArgOperand(0)->getType())) + Info.UniqName = getSPIRVFuncName(spv::OpSubgroupImageBlockWriteINTEL); + else + Info.UniqName = getSPIRVFuncName(spv::OpSubgroupBlockWriteINTEL); + unsigned numArgs = CI->getNumArgOperands(); + if (numArgs && CI->getArgOperand(numArgs - 1)->getType()->isVectorTy()) { + switch(CI->getArgOperand(numArgs - 1)->getType()->getVectorNumElements()) { + case 2: Info.Postfix = "_v2"; break; + case 4: Info.Postfix = "_v4"; break; + case 8: Info.Postfix = "_v8"; break; + default: break; + } + } + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + mutateCallInstSPIRV(M, CI, + [=](CallInst *, std::vector<Value *> &Args) { + Info.PostProc(Args); + return Info.UniqName + Info.Postfix; + }, + &Attrs); +} + +} + +INITIALIZE_PASS_BEGIN(OCL20ToSPIRV, "cl20tospv", "Transform OCL 2.0 to SPIR-V", + false, false) +INITIALIZE_PASS_DEPENDENCY(OCLTypeToSPIRV) +INITIALIZE_PASS_END(OCL20ToSPIRV, "cl20tospv", "Transform OCL 2.0 to SPIR-V", + false, false) + +ModulePass *llvm::createOCL20ToSPIRV() { + return new OCL20ToSPIRV(); +} diff --git a/lib/SPIRV/SPIRVInternal.h b/lib/SPIRV/SPIRVInternal.h index d29bda7..520defe 100644 --- a/lib/SPIRV/SPIRVInternal.h +++ b/lib/SPIRV/SPIRVInternal.h @@ -1,934 +1,934 @@ -//===- LLVMSPIRVInternal.h - SPIR-V internal header file --------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file declares classes and functions shared by SPIR-V reader/writer.
-///
-//===----------------------------------------------------------------------===//
-#ifndef LLVMSPIRVINTERNAL_HPP_
-#define LLVMSPIRVINTERNAL_HPP_
-
-#include "libSPIRV/SPIRVUtil.h"
-#include "libSPIRV/SPIRVEnum.h"
-#include "libSPIRV/SPIRVNameMapEnum.h"
-#include "libSPIRV/SPIRVError.h"
-#include "libSPIRV/SPIRVType.h"
-#include "NameMangleAPI.h"
-
-#include "llvm/IR/Attributes.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/Instructions.h"
-#include "SPIRV.h"
-
-#include <utility>
-#include <functional>
-
-using namespace SPIRV;
-using namespace llvm;
-
-namespace SPIRV{
-
- /// The LLVM/SPIR-V translator version used to fill the lower 16 bits of the
- /// generator's magic number in the generated SPIR-V module.
- /// This number should be bumped up whenever the generated SPIR-V changes.
- const static unsigned short kTranslatorVer = 14;
-
-#define SPCV_TARGET_LLVM_IMAGE_TYPE_ENCODE_ACCESS_QUAL 0
-// Workaround for SPIR 2 producer bug about kernel function calling convention.
-// This workaround checks metadata to determine if a function is kernel.
-#define SPCV_RELAX_KERNEL_CALLING_CONV 1
-
-class SPIRVOpaqueType;
-typedef SPIRVMap<std::string, Op, SPIRVOpaqueType>
- SPIRVOpaqueTypeOpCodeMap;
-
-// Ad hoc function used by LLVM/SPIRV converter for type casting
-#define SPCV_CAST "spcv.cast"
-#define LLVM_MEMCPY "llvm.memcpy"
-
-template<> inline void
-SPIRVMap<unsigned, Op>::init() {
-#define _SPIRV_OP(x,y) add(Instruction::x, Op##y);
- /* Casts */
- _SPIRV_OP(ZExt, UConvert)
- _SPIRV_OP(SExt, SConvert)
- _SPIRV_OP(Trunc, UConvert)
- _SPIRV_OP(FPToUI, ConvertFToU)
- _SPIRV_OP(FPToSI, ConvertFToS)
- _SPIRV_OP(UIToFP, ConvertUToF)
- _SPIRV_OP(SIToFP, ConvertSToF)
- _SPIRV_OP(FPTrunc, FConvert)
- _SPIRV_OP(FPExt, FConvert)
- _SPIRV_OP(PtrToInt, ConvertPtrToU)
- _SPIRV_OP(IntToPtr, ConvertUToPtr)
- _SPIRV_OP(BitCast, Bitcast)
- _SPIRV_OP(AddrSpaceCast, GenericCastToPtr)
- _SPIRV_OP(GetElementPtr, AccessChain)
- /*Binary*/
- _SPIRV_OP(And, BitwiseAnd)
- _SPIRV_OP(Or, BitwiseOr)
- _SPIRV_OP(Xor, BitwiseXor)
- _SPIRV_OP(Add, IAdd)
- _SPIRV_OP(FAdd, FAdd)
- _SPIRV_OP(Sub, ISub)
- _SPIRV_OP(FSub, FSub)
- _SPIRV_OP(Mul, IMul)
- _SPIRV_OP(FMul, FMul)
- _SPIRV_OP(UDiv, UDiv)
- _SPIRV_OP(SDiv, SDiv)
- _SPIRV_OP(FDiv, FDiv)
- _SPIRV_OP(SRem, SRem)
- _SPIRV_OP(FRem, FRem)
- _SPIRV_OP(URem, UMod)
- _SPIRV_OP(Shl, ShiftLeftLogical)
- _SPIRV_OP(LShr, ShiftRightLogical)
- _SPIRV_OP(AShr, ShiftRightArithmetic)
-#undef _SPIRV_OP
-}
-typedef SPIRVMap<unsigned, Op> OpCodeMap;
-
-template<> inline void
-SPIRVMap<CmpInst::Predicate, Op>::init() {
-#define _SPIRV_OP(x,y) add(CmpInst::x, Op##y);
- _SPIRV_OP(FCMP_OEQ, FOrdEqual)
- _SPIRV_OP(FCMP_OGT, FOrdGreaterThan)
- _SPIRV_OP(FCMP_OGE, FOrdGreaterThanEqual)
- _SPIRV_OP(FCMP_OLT, FOrdLessThan)
- _SPIRV_OP(FCMP_OLE, FOrdLessThanEqual)
- _SPIRV_OP(FCMP_ONE, FOrdNotEqual)
- _SPIRV_OP(FCMP_ORD, Ordered)
- _SPIRV_OP(FCMP_UNO, Unordered)
- _SPIRV_OP(FCMP_UEQ, FUnordEqual)
- _SPIRV_OP(FCMP_UGT, FUnordGreaterThan)
- _SPIRV_OP(FCMP_UGE, FUnordGreaterThanEqual)
- _SPIRV_OP(FCMP_ULT, FUnordLessThan)
- _SPIRV_OP(FCMP_ULE, FUnordLessThanEqual)
- _SPIRV_OP(FCMP_UNE, FUnordNotEqual)
- _SPIRV_OP(ICMP_EQ, IEqual)
- _SPIRV_OP(ICMP_NE, INotEqual)
- _SPIRV_OP(ICMP_UGT, UGreaterThan)
- _SPIRV_OP(ICMP_UGE, UGreaterThanEqual)
- _SPIRV_OP(ICMP_ULT, ULessThan)
- _SPIRV_OP(ICMP_ULE, ULessThanEqual)
- _SPIRV_OP(ICMP_SGT, SGreaterThan)
- _SPIRV_OP(ICMP_SGE, SGreaterThanEqual)
- _SPIRV_OP(ICMP_SLT, SLessThan)
- _SPIRV_OP(ICMP_SLE, SLessThanEqual)
-#undef _SPIRV_OP
-}
-typedef SPIRVMap<CmpInst::Predicate, Op> CmpMap;
-
-class IntBoolOpMapId;
-template<> inline void
-SPIRVMap<Op, Op, IntBoolOpMapId>::init() {
- add(OpNot, OpLogicalNot);
- add(OpBitwiseAnd, OpLogicalAnd);
- add(OpBitwiseOr, OpLogicalOr);
- add(OpBitwiseXor, OpLogicalNotEqual);
- add(OpIEqual, OpLogicalEqual);
- add(OpINotEqual, OpLogicalNotEqual);
-}
-typedef SPIRVMap<Op, Op, IntBoolOpMapId> IntBoolOpMap;
-
-#define SPIR_TARGETTRIPLE32 "spir-unknown-unknown"
-#define SPIR_TARGETTRIPLE64 "spir64-unknown-unknown"
-#define SPIR_DATALAYOUT32 "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32"\
- "-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32"\
- "-v32:32:32-v48:64:64-v64:64:64-v96:128:128"\
- "-v128:128:128-v192:256:256-v256:256:256"\
- "-v512:512:512-v1024:1024:1024"
-#define SPIR_DATALAYOUT64 "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32"\
- "-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32"\
- "-v32:32:32-v48:64:64-v64:64:64-v96:128:128"\
- "-v128:128:128-v192:256:256-v256:256:256"\
- "-v512:512:512-v1024:1024:1024"
-
-enum SPIRAddressSpace {
- SPIRAS_Private,
- SPIRAS_Global,
- SPIRAS_Constant,
- SPIRAS_Local,
- SPIRAS_Generic,
- SPIRAS_Count,
-};
-
-template<>inline void
-SPIRVMap<SPIRAddressSpace, std::string>::init() {
- add(SPIRAS_Private, "Private");
- add(SPIRAS_Global, "Global");
- add(SPIRAS_Constant, "Constant");
- add(SPIRAS_Local, "Local");
- add(SPIRAS_Generic, "Generic");
-}
-typedef SPIRVMap<SPIRAddressSpace, SPIRVStorageClassKind>
- SPIRAddrSpaceCapitalizedNameMap;
-
-template<> inline void
-SPIRVMap<SPIRAddressSpace, SPIRVStorageClassKind>::init() {
- add(SPIRAS_Private, StorageClassFunction);
- add(SPIRAS_Global, StorageClassCrossWorkgroup);
- add(SPIRAS_Constant, StorageClassUniformConstant);
- add(SPIRAS_Local, StorageClassWorkgroup);
- add(SPIRAS_Generic, StorageClassGeneric);
-}
-typedef SPIRVMap<SPIRAddressSpace, SPIRVStorageClassKind> SPIRSPIRVAddrSpaceMap;
-
-// Maps OCL builtin function to SPIRV builtin variable.
-template<> inline void
-SPIRVMap<std::string, SPIRVAccessQualifierKind>::init() {
- add("read_only", AccessQualifierReadOnly);
- add("write_only", AccessQualifierWriteOnly);
- add("read_write", AccessQualifierReadWrite);
-}
-typedef SPIRVMap<std::string, SPIRVAccessQualifierKind> SPIRSPIRVAccessQualifierMap;
-
-template<> inline void
-SPIRVMap<Attribute::AttrKind, SPIRVFuncParamAttrKind>::init() {
- add(Attribute::ZExt, FunctionParameterAttributeZext);
- add(Attribute::SExt, FunctionParameterAttributeSext);
- add(Attribute::ByVal, FunctionParameterAttributeByVal);
- add(Attribute::StructRet, FunctionParameterAttributeSret);
- add(Attribute::NoAlias, FunctionParameterAttributeNoAlias);
- add(Attribute::NoCapture, FunctionParameterAttributeNoCapture);
-}
-typedef SPIRVMap<Attribute::AttrKind, SPIRVFuncParamAttrKind>
- SPIRSPIRVFuncParamAttrMap;
-
-template<> inline void
-SPIRVMap<Attribute::AttrKind, SPIRVFunctionControlMaskKind>::init() {
- add(Attribute::ReadNone, FunctionControlPureMask);
- add(Attribute::ReadOnly, FunctionControlConstMask);
- add(Attribute::AlwaysInline, FunctionControlInlineMask);
- add(Attribute::NoInline, FunctionControlDontInlineMask);
-}
-typedef SPIRVMap<Attribute::AttrKind, SPIRVFunctionControlMaskKind>
- SPIRSPIRVFuncCtlMaskMap;
-
-class SPIRVExtSetShortName;
-template<> inline void
-SPIRVMap<SPIRVExtInstSetKind, std::string, SPIRVExtSetShortName>::init() {
- add(SPIRVEIS_OpenCL, "ocl");
-}
-typedef SPIRVMap<SPIRVExtInstSetKind, std::string, SPIRVExtSetShortName>
- SPIRVExtSetShortNameMap;
-
-#define SPIR_MD_KERNELS "opencl.kernels"
-#define SPIR_MD_COMPILER_OPTIONS "opencl.compiler.options"
-#define SPIR_MD_KERNEL_ARG_ADDR_SPACE "kernel_arg_addr_space"
-#define SPIR_MD_KERNEL_ARG_ACCESS_QUAL "kernel_arg_access_qual"
-#define SPIR_MD_KERNEL_ARG_TYPE "kernel_arg_type"
-#define SPIR_MD_KERNEL_ARG_BASE_TYPE "kernel_arg_base_type"
-#define SPIR_MD_KERNEL_ARG_TYPE_QUAL "kernel_arg_type_qual"
-#define SPIR_MD_KERNEL_ARG_NAME "kernel_arg_name"
-
-#define OCL_TYPE_NAME_SAMPLER_T "sampler_t"
-#define SPIR_TYPE_NAME_EVENT_T "opencl.event_t"
-#define SPIR_TYPE_NAME_CLK_EVENT_T "opencl.clk_event_t"
-#define SPIR_TYPE_NAME_BLOCK_T "opencl.block"
-#define SPIR_INTRINSIC_BLOCK_BIND "spir_block_bind"
-#define SPIR_INTRINSIC_GET_BLOCK_INVOKE "spir_get_block_invoke"
-#define SPIR_INTRINSIC_GET_BLOCK_CONTEXT "spir_get_block_context"
-#define SPIR_TEMP_NAME_PREFIX_BLOCK "block"
-#define SPIR_TEMP_NAME_PREFIX_CALL "call"
-
-namespace kLLVMTypeName {
- const static char StructPrefix[] = "struct.";
-}
-
-namespace kSPIRVImageSampledTypeName {
- const static char Float[] = "float";
- const static char Half[] = "half";
- const static char Int[] = "int";
- const static char UInt[] = "uint";
- const static char Void[] = "void";
-}
-
-namespace kSPIRVTypeName {
- const static char Delimiter = '.';
- const static char DeviceEvent[] = "DeviceEvent";
- const static char Event[] = "Event";
- const static char Image[] = "Image";
- const static char Pipe[] = "Pipe";
- const static char PostfixDelim = '_';
- const static char Prefix[] = "spirv";
- const static char PrefixAndDelim[] = "spirv.";
- const static char Queue[] = "Queue";
- const static char ReserveId[] = "ReserveId";
- const static char SampledImg[] = "SampledImage";
- const static char Sampler[] = "Sampler";
- const static char ConstantSampler[] = "ConstantSampler";
- const static char PipeStorage[] = "PipeStorage";
- const static char ConstantPipeStorage[] = "ConstantPipeStorage";
-}
-
-namespace kSPR2TypeName {
- const static char Delimiter = '.';
- const static char OCLPrefix[] = "opencl.";
- const static char ImagePrefix[] = "opencl.image";
- const static char Pipe[] = "opencl.pipe_t";
- const static char Sampler[] = "opencl.sampler_t";
- const static char Event[] = "opencl.event_t";
-}
-
-namespace kAccessQualName {
- const static char ReadOnly[] = "read_only";
- const static char WriteOnly[] = "write_only";
- const static char ReadWrite[] = "read_write";
-}
-
-namespace kMangledName {
- const static char Sampler[] = "11ocl_sampler";
- const static char AtomicPrefixIncoming[] = "U7_Atomic";
- const static char AtomicPrefixInternal[] = "atomic_";
-}
-
-namespace kSPIRVName {
- const static char GroupPrefix[] = "group_";
- const static char Prefix[] = "__spirv_";
- const static char Postfix[] = "__";
- const static char ImageQuerySize[] = "ImageQuerySize";
- const static char ImageQuerySizeLod[] = "ImageQuerySizeLod";
- const static char ImageSampleExplicitLod[] = "ImageSampleExplicitLod";
- const static char ReservedPrefix[] = "reserved_";
- const static char SampledImage[] = "SampledImage";
- const static char TempSampledImage[] = "TempSampledImage";
-}
-
-namespace kSPIRVPostfix {
- const static char Sat[] = "sat";
- const static char Rtz[] = "rtz";
- const static char Rte[] = "rte";
- const static char Rtp[] = "rtp";
- const static char Rtn[] = "rtn";
- const static char Rt[] = "rt";
- const static char Return[] = "R";
- const static char Divider[] = "_";
- /// Divider between extended instruction name and postfix
- const static char ExtDivider[] = "__";
-}
-
-namespace kSPIRVMD {
- const static char Capability[] = "spirv.Capability";
- const static char EntryPoint[] = "spirv.EntryPoint";
- const static char ExecutionMode[] = "spirv.ExecutionMode";
- const static char Extension[] = "spirv.Extension";
- const static char Generator[] = "spirv.Generator";
- const static char Source[] = "spirv.Source";
- const static char SourceExtension[] = "spirv.SourceExtension";
- const static char MemoryModel[] = "spirv.MemoryModel";
-}
-
-namespace kSPIR2MD {
- const static char Extensions[] = "opencl.used.extensions";
- const static char FPContract[] = "opencl.enable.FP_CONTRACT";
- const static char OCLVer[] = "opencl.ocl.version";
- const static char OptFeatures[] = "opencl.used.optional.core.features";
- const static char SPIRVer[] = "opencl.spir.version";
- const static char VecTyHint[] = "vec_type_hint";
- const static char WGSize[] = "reqd_work_group_size";
- const static char WGSizeHint[] = "work_group_size_hint";
-}
-
-enum Spir2SamplerKind {
- CLK_ADDRESS_NONE = 0x0000,
- CLK_ADDRESS_CLAMP = 0x0004,
- CLK_ADDRESS_CLAMP_TO_EDGE = 0x0002,
- CLK_ADDRESS_REPEAT = 0x0006,
- CLK_ADDRESS_MIRRORED_REPEAT = 0x0008,
- CLK_NORMALIZED_COORDS_FALSE = 0x0000,
- CLK_NORMALIZED_COORDS_TRUE = 0x0001,
- CLK_FILTER_NEAREST = 0x0010,
- CLK_FILTER_LINEAR = 0x0020,
-};
-
-
-/// Additional information for mangling a function argument type.
-struct BuiltinArgTypeMangleInfo {
- bool IsSigned;
- bool IsVoidPtr;
- bool IsEnum;
- bool IsSampler;
- bool IsAtomic;
- bool IsLocalArgBlock;
- SPIR::TypePrimitiveEnum Enum;
- unsigned Attr;
- BuiltinArgTypeMangleInfo():IsSigned(true), IsVoidPtr(false), IsEnum(false),
- IsSampler(false), IsAtomic(false), IsLocalArgBlock(false),
- Enum(SPIR::PRIMITIVE_NONE), Attr(0)
- {}
-};
-
-/// Information for mangling builtin function.
-class BuiltinFuncMangleInfo {
-public:
- /// Translate builtin function name and set
- /// argument attributes and unsigned args.
- BuiltinFuncMangleInfo(const std::string &UniqName = "") : LocalArgBlockIdx(-1),
- VarArgIdx(-1) {
- if (!UniqName.empty())
- init(UniqName);
- }
- virtual ~BuiltinFuncMangleInfo(){}
- const std::string &getUnmangledName() const { return UnmangledName; }
- void addUnsignedArg(int Ndx) { UnsignedArgs.insert(Ndx);}
- void addVoidPtrArg(int Ndx) { VoidPtrArgs.insert(Ndx);}
- void addSamplerArg(int Ndx) { SamplerArgs.insert(Ndx);}
- void addAtomicArg(int Ndx) { AtomicArgs.insert(Ndx);}
- void setLocalArgBlock(int Ndx) {
- assert(0 <= Ndx && "it is not allowed to set less than zero index");
- LocalArgBlockIdx = Ndx;
- }
- void setEnumArg(int Ndx, SPIR::TypePrimitiveEnum Enum) {
- EnumArgs[Ndx] = Enum;}
- void setArgAttr(int Ndx, unsigned Attr) {
- Attrs[Ndx] = Attr;}
- void setVarArg(int Ndx) {
- assert(0 <= Ndx && "it is not allowed to set less than zero index");
- VarArgIdx = Ndx;
- }
- bool isArgUnsigned(int Ndx) {
- return UnsignedArgs.count(-1) || UnsignedArgs.count(Ndx);}
- bool isArgVoidPtr(int Ndx) {
- return VoidPtrArgs.count(-1) || VoidPtrArgs.count(Ndx);}
- bool isArgSampler(int Ndx) {
- return SamplerArgs.count(Ndx);}
- bool isArgAtomic(int Ndx) {
- return AtomicArgs.count(Ndx);}
- bool isLocalArgBlock(int Ndx) {
- return LocalArgBlockIdx == Ndx;}
- bool isArgEnum(int Ndx, SPIR::TypePrimitiveEnum *Enum = nullptr) {
- auto Loc = EnumArgs.find(Ndx);
- if (Loc == EnumArgs.end())
- Loc = EnumArgs.find(-1);
- if (Loc == EnumArgs.end())
- return false;
- if (Enum)
- *Enum = Loc->second;
- return true;
- }
- unsigned getArgAttr(int Ndx) {
- auto Loc = Attrs.find(Ndx);
- if (Loc == Attrs.end())
- Loc = Attrs.find(-1);
- if (Loc == Attrs.end())
- return 0;
- return Loc->second;
- }
- // get ellipsis index, single ellipsis at the end of the function is possible only
- // return value < 0 if none
- int getVarArg() const {
- return VarArgIdx;
- }
- BuiltinArgTypeMangleInfo getTypeMangleInfo(int Ndx) {
- BuiltinArgTypeMangleInfo Info;
- Info.IsSigned = !isArgUnsigned(Ndx);
- Info.IsVoidPtr = isArgVoidPtr(Ndx);
- Info.IsEnum = isArgEnum(Ndx, &Info.Enum);
- Info.IsSampler = isArgSampler(Ndx);
- Info.IsAtomic = isArgAtomic(Ndx);
- Info.IsLocalArgBlock = isLocalArgBlock(Ndx);
- Info.Attr = getArgAttr(Ndx);
- return Info;
- }
- virtual void init(const std::string &UniqUnmangledName){
- UnmangledName = UniqUnmangledName;
- }
-protected:
- std::string UnmangledName;
- std::set<int> UnsignedArgs; // unsigned arguments, or -1 if all are unsigned
- std::set<int> VoidPtrArgs; // void pointer arguments, or -1 if all are void
- // pointer
- std::set<int> SamplerArgs; // sampler arguments
- std::set<int> AtomicArgs; // atomic arguments
- std::map<int, SPIR::TypePrimitiveEnum> EnumArgs; // enum arguments
- std::map<int, unsigned> Attrs; // argument attributes
- int LocalArgBlockIdx; // index of a block with local arguments, idx < 0 if none
- int VarArgIdx; // index of ellipsis argument, idx < 0 if none
-};
-
-/// \returns a vector of types for a collection of values.
-template<class T>
-std::vector<Type *>
-getTypes(T V) {
- std::vector<Type *> Tys;
- for (auto &I:V)
- Tys.push_back(I->getType());
- 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,
- Attribute::AttrKind Attr);
-void saveLLVMModule(Module *M, const std::string &OutputFile);
-std::string mapSPIRVTypeToOCLType(SPIRVType* Ty, bool Signed);
-std::string mapLLVMTypeToOCLType(const Type* Ty, bool Signed);
-SPIRVDecorate *mapPostfixToDecorate(StringRef Postfix, SPIRVEntry *Target);
-
-/// Add decorations to a SPIR-V entry.
-/// \param Decs Each string is a postfix without _ at the beginning.
-SPIRVValue *addDecorations(SPIRVValue *Target,
- const SmallVectorImpl<std::string>& Decs);
-
-PointerType *getOrCreateOpaquePtrType(Module *M, const std::string &Name,
- unsigned AddrSpace = SPIRAS_Global);
-PointerType* getSamplerType(Module *M);
-PointerType* getPipeStorageType(Module *M);
-void getFunctionTypeParameterTypes(llvm::FunctionType* FT,
- std::vector<Type*>& ArgTys);
-Function *getOrCreateFunction(Module *M, Type *RetTy,
- ArrayRef<Type *> ArgTypes, StringRef Name,
- BuiltinFuncMangleInfo *Mangle = nullptr,
- AttributeList *Attrs = nullptr, bool takeName = true);
-
-/// Get function call arguments.
-/// \param Start Starting index.
-/// \param End Ending index.
-std::vector<Value *> getArguments(CallInst* CI, unsigned Start = 0,
- unsigned End = 0);
-
-/// Get constant function call argument as an integer.
-/// \param I argument index.
-uint64_t getArgAsInt(CallInst *CI, unsigned I);
-
-/// Get constant function call argument as type \param T.
-/// \param I argument index.
-template<typename T>
-T getArgAs(CallInst *CI, unsigned I){
- return static_cast<T>(getArgAsInt(CI, I));
-}
-
-/// Get constant function call argument as a Scope enum.
-/// \param I argument index.
-Scope getArgAsScope(CallInst *CI, unsigned I);
-
-/// Get constant function call argument as a Decoration enum.
-/// \param I argument index.
-Decoration getArgAsDecoration(CallInst *CI, unsigned I);
-
-bool isPointerToOpaqueStructType(llvm::Type* Ty);
-bool isPointerToOpaqueStructType(llvm::Type* Ty, const std::string &Name);
-
-/// Check if a type is OCL image type.
-/// \return type name without "opencl." prefix.
-bool isOCLImageType(llvm::Type* Ty, StringRef *Name = nullptr);
-
-/// \param BaseTyName is the type name as in spirv.BaseTyName.Postfixes
-/// \param Postfix contains postfixes extracted from the SPIR-V image
-/// type name as spirv.BaseTyName.Postfixes.
-bool
-isSPIRVType(llvm::Type* Ty, StringRef BaseTyName, StringRef *Postfix = 0);
-
-/// Decorate a function name as __spirv_{Name}_
-std::string decorateSPIRVFunction(const std::string &S);
-
-/// Remove prefix/postfix from __spirv_{Name}_
-std::string undecorateSPIRVFunction(const std::string &S);
-
-/// Check if a function has decorated name as __spirv_{Name}_
-/// and get the original name.
-bool isDecoratedSPIRVFunc(const Function *F, std::string *UndecName = nullptr);
-
-/// Get a canonical function name for a SPIR-V op code.
-std::string getSPIRVFuncName(Op OC, StringRef PostFix = "");
-
-std::string getSPIRVFuncName(Op OC, const Type *pRetTy, bool IsSigned = false);
-
-/// Get a canonical function name for a SPIR-V extended instruction
-std::string getSPIRVExtFuncName(SPIRVExtInstSetKind Set, unsigned ExtOp,
- StringRef PostFix = "");
-
-/// Get SPIR-V op code given the canonical function name.
-/// Assume \param Name is either IA64 mangled or unmangled, and the unmangled
-/// name takes the __spirv_{OpName}_{Postfixes} format.
-/// \return op code if the unmangled function name is a valid op code name,
-/// otherwise return OpNop.
-/// \param Dec contains decorations decoded from function name if it is
-/// not nullptr.
-Op getSPIRVFuncOC(const std::string& Name,
- SmallVectorImpl<std::string> *Dec = nullptr);
-
-/// Get SPIR-V builtin variable enum given the canonical builtin name
-/// Assume \param Name is in format __spirv_BuiltIn{Name}
-/// \return false if \param Name is not a valid builtin name.
-bool getSPIRVBuiltin(const std::string &Name, spv::BuiltIn &Builtin);
-
-/// \param Name LLVM function name
-/// \param DemangledName demanged name of the OpenCL built-in function
-/// \returns true if Name is the name of the OpenCL built-in function,
-/// false for other functions
-bool oclIsBuiltin(const StringRef &Name, std::string *DemangledName = nullptr,
- bool isCPP = false);
-
-/// Check if a function type is void(void).
-bool isVoidFuncTy(FunctionType *FT);
-
-/// \returns true if \p T is a function pointer type.
-bool isFunctionPointerType(Type *T);
-
-/// \returns true if function \p F has function pointer type argument.
-/// \param AI points to the function pointer type argument if returns true.
-bool hasFunctionPointerArg(Function *F, Function::arg_iterator& AI);
-
-/// \returns true if function \p F has array type argument.
-bool hasArrayArg(Function *F);
-
-/// Mutates function call instruction by changing the arguments.
-/// \param ArgMutate mutates the function arguments.
-/// \return mutated call instruction.
-CallInst *mutateCallInst(Module *M, CallInst *CI,
- std::function<std::string (CallInst *, std::vector<Value *> &)>ArgMutate,
- BuiltinFuncMangleInfo *Mangle = nullptr, AttributeList *Attrs = nullptr,
- bool takeName = false);
-
-/// Mutates function call instruction by changing the arguments and return
-/// value.
-/// \param ArgMutate mutates the function arguments.
-/// \param RetMutate mutates the return value.
-/// \return mutated instruction.
-Instruction *mutateCallInst(Module *M, CallInst *CI,
- std::function<std::string (CallInst *, std::vector<Value *> &,
- Type *&RetTy)> ArgMutate,
- std::function<Instruction *(CallInst *)> RetMutate,
- BuiltinFuncMangleInfo *Mangle = nullptr, AttributeList *Attrs = nullptr,
- bool takeName = false);
-
-/// Mutate call instruction to call SPIR-V builtin function.
-CallInst *
-mutateCallInstSPIRV(Module *M, CallInst *CI,
- std::function<std::string (CallInst *, std::vector<Value *> &)>ArgMutate,
- AttributeList *Attrs = nullptr);
-
-/// Mutate call instruction to call SPIR-V builtin function.
-Instruction *
-mutateCallInstSPIRV(Module *M, CallInst *CI,
- std::function<std::string (CallInst *, std::vector<Value *> &,
- Type *&RetTy)> ArgMutate,
- std::function<Instruction *(CallInst *)> RetMutate,
- AttributeList *Attrs = nullptr);
-
-/// Mutate function by change the arguments.
-/// \param ArgMutate mutates the function arguments.
-/// \param TakeName Take the original function's name if a new function with
-/// different type needs to be created.
-void mutateFunction(Function *F,
- std::function<std::string (CallInst *, std::vector<Value *> &)>ArgMutate,
- BuiltinFuncMangleInfo *Mangle = nullptr, AttributeList *Attrs = nullptr,
- bool TakeName = true);
-
-/// Add a call instruction at \p Pos.
-CallInst *addCallInst(Module *M, StringRef FuncName, Type *RetTy,
- ArrayRef<Value *> Args, AttributeList *Attrs, Instruction *Pos,
- BuiltinFuncMangleInfo *Mangle = nullptr,
- StringRef InstName = SPIR_TEMP_NAME_PREFIX_CALL,
- bool TakeFuncName = true);
-
-/// Add a call instruction for SPIR-V builtin function.
-CallInst *
-addCallInstSPIRV(Module *M, StringRef FuncName, Type *RetTy,
- ArrayRef<Value *> Args,
- AttributeList *Attrs, Instruction *Pos, StringRef InstName);
-
-/// Add a call of spir_block_bind function.
-CallInst *
-addBlockBind(Module *M, Function *InvokeFunc, Value *BlkCtx, Value *CtxLen,
- Value *CtxAlign, Instruction *InsPos,
- StringRef InstName = SPIR_TEMP_NAME_PREFIX_BLOCK);
-
-typedef std::pair<std::vector<Value *>::iterator,
- std::vector<Value *>::iterator> ValueVecRange;
-
-/// Add a vector at \param InsPos.
-Value *
-addVector(Instruction *InsPos, ValueVecRange Range);
-
-/// Replace scalar values with a vector created at \param InsPos.
-void
-makeVector(Instruction *InsPos, std::vector<Value *> &Ops,
- ValueVecRange Range);
-
-/// Expand a vector type value in \param Ops at index \param VecPos.
-/// Generate extract element instructions at \param InsPos and replace
-/// the vector type value with scalar type values.
-/// If the value to be expanded is not vector type, do nothing.
-void
-expandVector(Instruction *InsPos, std::vector<Value *> &Ops, size_t VecPos);
-
-/// Get size_t type.
-IntegerType *getSizetType(Module *M);
-
-/// Get void(void) function type.
-Type *getVoidFuncType(Module *M);
-
-/// Get void(void) function pointer type.
-Type *getVoidFuncPtrType(Module *M, unsigned AddrSpace = 0);
-
-/// Get a 64 bit integer constant.
-ConstantInt *getInt64(Module *M, int64_t value);
-
-/// Get a 32 bit integer constant.
-ConstantInt *getInt32(Module *M, int value);
-
-/// Get a 32 bit unsigned integer constant.
-ConstantInt *getUInt32(Module *M, unsigned value);
-
-/// Get a 16 bit unsigned integer constant.
-ConstantInt *getUInt16(Module *M, unsigned short value);
-
-// Get a 32 bit floating point constant.
-Constant *getFloat32(Module *M, float value);
-
-/// Get a 32 bit integer constant vector.
-std::vector<Value *> getInt32(Module *M, const std::vector<int> &value);
-
-/// Get a size_t type constant.
-ConstantInt *getSizet(Module *M, uint64_t value);
-
-/// 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 a named metadata as a set of string.
-/// Assume the named metadata has one or more operands each of which might
-/// contain set of strings. For instance:
-/// !opencl.used.optional.core.features = !{!0}
-/// !0 = !{!"cl_doubles", !"cl_images"}
-/// or if we linked two modules we may have
-/// !opencl.used.optional.core.features = !{!0, !1}
-/// !0 = !{!"cl_doubles"}
-/// !1 = !{!"cl_images"}
-std::set<std::string> getNamedMDAsStringSet(Module *M,
- const std::string &MDName);
-
-/// Get SPIR-V language by SPIR-V metadata spirv.Source
-std::tuple<unsigned, unsigned, std::string>
-getSPIRVSource(Module *M);
-
-/// 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);
-
-/// Get postfix for given decoration.
-/// The returned postfix does not include "_" at the beginning.
-std::string getPostfix(Decoration Dec, unsigned Value = 0);
-
-/// Get postfix _R{ReturnType} for return type
-/// The returned postfix does not includ "_" at the beginning
-std::string getPostfixForReturnType(CallInst *CI, bool IsSigned = false);
-std::string getPostfixForReturnType(const Type *pRetTy, bool IsSigned = false);
-
-Constant *
-getScalarOrVectorConstantInt(Type *T, uint64_t V, bool isSigned = false);
-
-/// Get a constant int or a constant int array.
-/// \param T is the type of the constant. It should be an integer type or
-// an integer pointer type.
-/// \param Len is the length of the array.
-/// \param V is the value to fill the array.
-Value *
-getScalarOrArrayConstantInt(Instruction *P, Type *T, unsigned Len, uint64_t V,
- bool isSigned = false);
-
-/// Get the array from GEP.
-/// \param V is a GEP whose pointer operand is a pointer to an array of size
-/// \param Size.
-Value *
-getScalarOrArray(Value *V, unsigned Size, Instruction *Pos);
-
-void
-dumpUsers(Value* V, StringRef Prompt = "");
-
-/// Get SPIR-V type name as spirv.BaseTyName.Postfixes.
-std::string
-getSPIRVTypeName(StringRef BaseTyName, StringRef Postfixes = "");
-
-/// Checks if given type name is either ConstantSampler or ConsantPipeStorage.
+//===- LLVMSPIRVInternal.h - SPIR-V internal header file --------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file declares classes and functions shared by SPIR-V reader/writer. +/// +//===----------------------------------------------------------------------===// +#ifndef LLVMSPIRVINTERNAL_HPP_ +#define LLVMSPIRVINTERNAL_HPP_ + +#include "libSPIRV/SPIRVUtil.h" +#include "libSPIRV/SPIRVEnum.h" +#include "libSPIRV/SPIRVNameMapEnum.h" +#include "libSPIRV/SPIRVError.h" +#include "libSPIRV/SPIRVType.h" +#include "NameMangleAPI.h" + +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "SPIRV.h" + +#include <utility> +#include <functional> + +using namespace SPIRV; +using namespace llvm; + +namespace SPIRV{ + + /// The LLVM/SPIR-V translator version used to fill the lower 16 bits of the + /// generator's magic number in the generated SPIR-V module. + /// This number should be bumped up whenever the generated SPIR-V changes. + const static unsigned short kTranslatorVer = 14; + +#define SPCV_TARGET_LLVM_IMAGE_TYPE_ENCODE_ACCESS_QUAL 0 +// Workaround for SPIR 2 producer bug about kernel function calling convention. +// This workaround checks metadata to determine if a function is kernel. +#define SPCV_RELAX_KERNEL_CALLING_CONV 1 + +class SPIRVOpaqueType; +typedef SPIRVMap<std::string, Op, SPIRVOpaqueType> + SPIRVOpaqueTypeOpCodeMap; + +// Ad hoc function used by LLVM/SPIRV converter for type casting +#define SPCV_CAST "spcv.cast" +#define LLVM_MEMCPY "llvm.memcpy" + +template<> inline void +SPIRVMap<unsigned, Op>::init() { +#define _SPIRV_OP(x,y) add(Instruction::x, Op##y); + /* Casts */ + _SPIRV_OP(ZExt, UConvert) + _SPIRV_OP(SExt, SConvert) + _SPIRV_OP(Trunc, UConvert) + _SPIRV_OP(FPToUI, ConvertFToU) + _SPIRV_OP(FPToSI, ConvertFToS) + _SPIRV_OP(UIToFP, ConvertUToF) + _SPIRV_OP(SIToFP, ConvertSToF) + _SPIRV_OP(FPTrunc, FConvert) + _SPIRV_OP(FPExt, FConvert) + _SPIRV_OP(PtrToInt, ConvertPtrToU) + _SPIRV_OP(IntToPtr, ConvertUToPtr) + _SPIRV_OP(BitCast, Bitcast) + _SPIRV_OP(AddrSpaceCast, GenericCastToPtr) + _SPIRV_OP(GetElementPtr, AccessChain) + /*Binary*/ + _SPIRV_OP(And, BitwiseAnd) + _SPIRV_OP(Or, BitwiseOr) + _SPIRV_OP(Xor, BitwiseXor) + _SPIRV_OP(Add, IAdd) + _SPIRV_OP(FAdd, FAdd) + _SPIRV_OP(Sub, ISub) + _SPIRV_OP(FSub, FSub) + _SPIRV_OP(Mul, IMul) + _SPIRV_OP(FMul, FMul) + _SPIRV_OP(UDiv, UDiv) + _SPIRV_OP(SDiv, SDiv) + _SPIRV_OP(FDiv, FDiv) + _SPIRV_OP(SRem, SRem) + _SPIRV_OP(FRem, FRem) + _SPIRV_OP(URem, UMod) + _SPIRV_OP(Shl, ShiftLeftLogical) + _SPIRV_OP(LShr, ShiftRightLogical) + _SPIRV_OP(AShr, ShiftRightArithmetic) +#undef _SPIRV_OP +} +typedef SPIRVMap<unsigned, Op> OpCodeMap; + +template<> inline void +SPIRVMap<CmpInst::Predicate, Op>::init() { +#define _SPIRV_OP(x,y) add(CmpInst::x, Op##y); + _SPIRV_OP(FCMP_OEQ, FOrdEqual) + _SPIRV_OP(FCMP_OGT, FOrdGreaterThan) + _SPIRV_OP(FCMP_OGE, FOrdGreaterThanEqual) + _SPIRV_OP(FCMP_OLT, FOrdLessThan) + _SPIRV_OP(FCMP_OLE, FOrdLessThanEqual) + _SPIRV_OP(FCMP_ONE, FOrdNotEqual) + _SPIRV_OP(FCMP_ORD, Ordered) + _SPIRV_OP(FCMP_UNO, Unordered) + _SPIRV_OP(FCMP_UEQ, FUnordEqual) + _SPIRV_OP(FCMP_UGT, FUnordGreaterThan) + _SPIRV_OP(FCMP_UGE, FUnordGreaterThanEqual) + _SPIRV_OP(FCMP_ULT, FUnordLessThan) + _SPIRV_OP(FCMP_ULE, FUnordLessThanEqual) + _SPIRV_OP(FCMP_UNE, FUnordNotEqual) + _SPIRV_OP(ICMP_EQ, IEqual) + _SPIRV_OP(ICMP_NE, INotEqual) + _SPIRV_OP(ICMP_UGT, UGreaterThan) + _SPIRV_OP(ICMP_UGE, UGreaterThanEqual) + _SPIRV_OP(ICMP_ULT, ULessThan) + _SPIRV_OP(ICMP_ULE, ULessThanEqual) + _SPIRV_OP(ICMP_SGT, SGreaterThan) + _SPIRV_OP(ICMP_SGE, SGreaterThanEqual) + _SPIRV_OP(ICMP_SLT, SLessThan) + _SPIRV_OP(ICMP_SLE, SLessThanEqual) +#undef _SPIRV_OP +} +typedef SPIRVMap<CmpInst::Predicate, Op> CmpMap; + +class IntBoolOpMapId; +template<> inline void +SPIRVMap<Op, Op, IntBoolOpMapId>::init() { + add(OpNot, OpLogicalNot); + add(OpBitwiseAnd, OpLogicalAnd); + add(OpBitwiseOr, OpLogicalOr); + add(OpBitwiseXor, OpLogicalNotEqual); + add(OpIEqual, OpLogicalEqual); + add(OpINotEqual, OpLogicalNotEqual); +} +typedef SPIRVMap<Op, Op, IntBoolOpMapId> IntBoolOpMap; + +#define SPIR_TARGETTRIPLE32 "spir-unknown-unknown" +#define SPIR_TARGETTRIPLE64 "spir64-unknown-unknown" +#define SPIR_DATALAYOUT32 "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32"\ + "-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32"\ + "-v32:32:32-v48:64:64-v64:64:64-v96:128:128"\ + "-v128:128:128-v192:256:256-v256:256:256"\ + "-v512:512:512-v1024:1024:1024" +#define SPIR_DATALAYOUT64 "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32"\ + "-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32"\ + "-v32:32:32-v48:64:64-v64:64:64-v96:128:128"\ + "-v128:128:128-v192:256:256-v256:256:256"\ + "-v512:512:512-v1024:1024:1024" + +enum SPIRAddressSpace { + SPIRAS_Private, + SPIRAS_Global, + SPIRAS_Constant, + SPIRAS_Local, + SPIRAS_Generic, + SPIRAS_Count, +}; + +template<>inline void +SPIRVMap<SPIRAddressSpace, std::string>::init() { + add(SPIRAS_Private, "Private"); + add(SPIRAS_Global, "Global"); + add(SPIRAS_Constant, "Constant"); + add(SPIRAS_Local, "Local"); + add(SPIRAS_Generic, "Generic"); +} +typedef SPIRVMap<SPIRAddressSpace, SPIRVStorageClassKind> + SPIRAddrSpaceCapitalizedNameMap; + +template<> inline void +SPIRVMap<SPIRAddressSpace, SPIRVStorageClassKind>::init() { + add(SPIRAS_Private, StorageClassFunction); + add(SPIRAS_Global, StorageClassCrossWorkgroup); + add(SPIRAS_Constant, StorageClassUniformConstant); + add(SPIRAS_Local, StorageClassWorkgroup); + add(SPIRAS_Generic, StorageClassGeneric); +} +typedef SPIRVMap<SPIRAddressSpace, SPIRVStorageClassKind> SPIRSPIRVAddrSpaceMap; + +// Maps OCL builtin function to SPIRV builtin variable. +template<> inline void +SPIRVMap<std::string, SPIRVAccessQualifierKind>::init() { + add("read_only", AccessQualifierReadOnly); + add("write_only", AccessQualifierWriteOnly); + add("read_write", AccessQualifierReadWrite); +} +typedef SPIRVMap<std::string, SPIRVAccessQualifierKind> SPIRSPIRVAccessQualifierMap; + +template<> inline void +SPIRVMap<Attribute::AttrKind, SPIRVFuncParamAttrKind>::init() { + add(Attribute::ZExt, FunctionParameterAttributeZext); + add(Attribute::SExt, FunctionParameterAttributeSext); + add(Attribute::ByVal, FunctionParameterAttributeByVal); + add(Attribute::StructRet, FunctionParameterAttributeSret); + add(Attribute::NoAlias, FunctionParameterAttributeNoAlias); + add(Attribute::NoCapture, FunctionParameterAttributeNoCapture); +} +typedef SPIRVMap<Attribute::AttrKind, SPIRVFuncParamAttrKind> + SPIRSPIRVFuncParamAttrMap; + +template<> inline void +SPIRVMap<Attribute::AttrKind, SPIRVFunctionControlMaskKind>::init() { + add(Attribute::ReadNone, FunctionControlPureMask); + add(Attribute::ReadOnly, FunctionControlConstMask); + add(Attribute::AlwaysInline, FunctionControlInlineMask); + add(Attribute::NoInline, FunctionControlDontInlineMask); +} +typedef SPIRVMap<Attribute::AttrKind, SPIRVFunctionControlMaskKind> + SPIRSPIRVFuncCtlMaskMap; + +class SPIRVExtSetShortName; +template<> inline void +SPIRVMap<SPIRVExtInstSetKind, std::string, SPIRVExtSetShortName>::init() { + add(SPIRVEIS_OpenCL, "ocl"); +} +typedef SPIRVMap<SPIRVExtInstSetKind, std::string, SPIRVExtSetShortName> + SPIRVExtSetShortNameMap; + +#define SPIR_MD_KERNELS "opencl.kernels" +#define SPIR_MD_COMPILER_OPTIONS "opencl.compiler.options" +#define SPIR_MD_KERNEL_ARG_ADDR_SPACE "kernel_arg_addr_space" +#define SPIR_MD_KERNEL_ARG_ACCESS_QUAL "kernel_arg_access_qual" +#define SPIR_MD_KERNEL_ARG_TYPE "kernel_arg_type" +#define SPIR_MD_KERNEL_ARG_BASE_TYPE "kernel_arg_base_type" +#define SPIR_MD_KERNEL_ARG_TYPE_QUAL "kernel_arg_type_qual" +#define SPIR_MD_KERNEL_ARG_NAME "kernel_arg_name" + +#define OCL_TYPE_NAME_SAMPLER_T "sampler_t" +#define SPIR_TYPE_NAME_EVENT_T "opencl.event_t" +#define SPIR_TYPE_NAME_CLK_EVENT_T "opencl.clk_event_t" +#define SPIR_TYPE_NAME_BLOCK_T "opencl.block" +#define SPIR_INTRINSIC_BLOCK_BIND "spir_block_bind" +#define SPIR_INTRINSIC_GET_BLOCK_INVOKE "spir_get_block_invoke" +#define SPIR_INTRINSIC_GET_BLOCK_CONTEXT "spir_get_block_context" +#define SPIR_TEMP_NAME_PREFIX_BLOCK "block" +#define SPIR_TEMP_NAME_PREFIX_CALL "call" + +namespace kLLVMTypeName { + const static char StructPrefix[] = "struct."; +} + +namespace kSPIRVImageSampledTypeName { + const static char Float[] = "float"; + const static char Half[] = "half"; + const static char Int[] = "int"; + const static char UInt[] = "uint"; + const static char Void[] = "void"; +} + +namespace kSPIRVTypeName { + const static char Delimiter = '.'; + const static char DeviceEvent[] = "DeviceEvent"; + const static char Event[] = "Event"; + const static char Image[] = "Image"; + const static char Pipe[] = "Pipe"; + const static char PostfixDelim = '_'; + const static char Prefix[] = "spirv"; + const static char PrefixAndDelim[] = "spirv."; + const static char Queue[] = "Queue"; + const static char ReserveId[] = "ReserveId"; + const static char SampledImg[] = "SampledImage"; + const static char Sampler[] = "Sampler"; + const static char ConstantSampler[] = "ConstantSampler"; + const static char PipeStorage[] = "PipeStorage"; + const static char ConstantPipeStorage[] = "ConstantPipeStorage"; +} + +namespace kSPR2TypeName { + const static char Delimiter = '.'; + const static char OCLPrefix[] = "opencl."; + const static char ImagePrefix[] = "opencl.image"; + const static char Pipe[] = "opencl.pipe_t"; + const static char Sampler[] = "opencl.sampler_t"; + const static char Event[] = "opencl.event_t"; +} + +namespace kAccessQualName { + const static char ReadOnly[] = "read_only"; + const static char WriteOnly[] = "write_only"; + const static char ReadWrite[] = "read_write"; +} + +namespace kMangledName { + const static char Sampler[] = "11ocl_sampler"; + const static char AtomicPrefixIncoming[] = "U7_Atomic"; + const static char AtomicPrefixInternal[] = "atomic_"; +} + +namespace kSPIRVName { + const static char GroupPrefix[] = "group_"; + const static char Prefix[] = "__spirv_"; + const static char Postfix[] = "__"; + const static char ImageQuerySize[] = "ImageQuerySize"; + const static char ImageQuerySizeLod[] = "ImageQuerySizeLod"; + const static char ImageSampleExplicitLod[] = "ImageSampleExplicitLod"; + const static char ReservedPrefix[] = "reserved_"; + const static char SampledImage[] = "SampledImage"; + const static char TempSampledImage[] = "TempSampledImage"; +} + +namespace kSPIRVPostfix { + const static char Sat[] = "sat"; + const static char Rtz[] = "rtz"; + const static char Rte[] = "rte"; + const static char Rtp[] = "rtp"; + const static char Rtn[] = "rtn"; + const static char Rt[] = "rt"; + const static char Return[] = "R"; + const static char Divider[] = "_"; + /// Divider between extended instruction name and postfix + const static char ExtDivider[] = "__"; +} + +namespace kSPIRVMD { + const static char Capability[] = "spirv.Capability"; + const static char EntryPoint[] = "spirv.EntryPoint"; + const static char ExecutionMode[] = "spirv.ExecutionMode"; + const static char Extension[] = "spirv.Extension"; + const static char Generator[] = "spirv.Generator"; + const static char Source[] = "spirv.Source"; + const static char SourceExtension[] = "spirv.SourceExtension"; + const static char MemoryModel[] = "spirv.MemoryModel"; +} + +namespace kSPIR2MD { + const static char Extensions[] = "opencl.used.extensions"; + const static char FPContract[] = "opencl.enable.FP_CONTRACT"; + const static char OCLVer[] = "opencl.ocl.version"; + const static char OptFeatures[] = "opencl.used.optional.core.features"; + const static char SPIRVer[] = "opencl.spir.version"; + const static char VecTyHint[] = "vec_type_hint"; + const static char WGSize[] = "reqd_work_group_size"; + const static char WGSizeHint[] = "work_group_size_hint"; +} + +enum Spir2SamplerKind { + CLK_ADDRESS_NONE = 0x0000, + CLK_ADDRESS_CLAMP = 0x0004, + CLK_ADDRESS_CLAMP_TO_EDGE = 0x0002, + CLK_ADDRESS_REPEAT = 0x0006, + CLK_ADDRESS_MIRRORED_REPEAT = 0x0008, + CLK_NORMALIZED_COORDS_FALSE = 0x0000, + CLK_NORMALIZED_COORDS_TRUE = 0x0001, + CLK_FILTER_NEAREST = 0x0010, + CLK_FILTER_LINEAR = 0x0020, +}; + + +/// Additional information for mangling a function argument type. +struct BuiltinArgTypeMangleInfo { + bool IsSigned; + bool IsVoidPtr; + bool IsEnum; + bool IsSampler; + bool IsAtomic; + bool IsLocalArgBlock; + SPIR::TypePrimitiveEnum Enum; + unsigned Attr; + BuiltinArgTypeMangleInfo():IsSigned(true), IsVoidPtr(false), IsEnum(false), + IsSampler(false), IsAtomic(false), IsLocalArgBlock(false), + Enum(SPIR::PRIMITIVE_NONE), Attr(0) + {} +}; + +/// Information for mangling builtin function. +class BuiltinFuncMangleInfo { +public: + /// Translate builtin function name and set + /// argument attributes and unsigned args. + BuiltinFuncMangleInfo(const std::string &UniqName = "") : LocalArgBlockIdx(-1), + VarArgIdx(-1) { + if (!UniqName.empty()) + init(UniqName); + } + virtual ~BuiltinFuncMangleInfo(){} + const std::string &getUnmangledName() const { return UnmangledName; } + void addUnsignedArg(int Ndx) { UnsignedArgs.insert(Ndx);} + void addVoidPtrArg(int Ndx) { VoidPtrArgs.insert(Ndx);} + void addSamplerArg(int Ndx) { SamplerArgs.insert(Ndx);} + void addAtomicArg(int Ndx) { AtomicArgs.insert(Ndx);} + void setLocalArgBlock(int Ndx) { + assert(0 <= Ndx && "it is not allowed to set less than zero index"); + LocalArgBlockIdx = Ndx; + } + void setEnumArg(int Ndx, SPIR::TypePrimitiveEnum Enum) { + EnumArgs[Ndx] = Enum;} + void setArgAttr(int Ndx, unsigned Attr) { + Attrs[Ndx] = Attr;} + void setVarArg(int Ndx) { + assert(0 <= Ndx && "it is not allowed to set less than zero index"); + VarArgIdx = Ndx; + } + bool isArgUnsigned(int Ndx) { + return UnsignedArgs.count(-1) || UnsignedArgs.count(Ndx);} + bool isArgVoidPtr(int Ndx) { + return VoidPtrArgs.count(-1) || VoidPtrArgs.count(Ndx);} + bool isArgSampler(int Ndx) { + return SamplerArgs.count(Ndx);} + bool isArgAtomic(int Ndx) { + return AtomicArgs.count(Ndx);} + bool isLocalArgBlock(int Ndx) { + return LocalArgBlockIdx == Ndx;} + bool isArgEnum(int Ndx, SPIR::TypePrimitiveEnum *Enum = nullptr) { + auto Loc = EnumArgs.find(Ndx); + if (Loc == EnumArgs.end()) + Loc = EnumArgs.find(-1); + if (Loc == EnumArgs.end()) + return false; + if (Enum) + *Enum = Loc->second; + return true; + } + unsigned getArgAttr(int Ndx) { + auto Loc = Attrs.find(Ndx); + if (Loc == Attrs.end()) + Loc = Attrs.find(-1); + if (Loc == Attrs.end()) + return 0; + return Loc->second; + } + // get ellipsis index, single ellipsis at the end of the function is possible only + // return value < 0 if none + int getVarArg() const { + return VarArgIdx; + } + BuiltinArgTypeMangleInfo getTypeMangleInfo(int Ndx) { + BuiltinArgTypeMangleInfo Info; + Info.IsSigned = !isArgUnsigned(Ndx); + Info.IsVoidPtr = isArgVoidPtr(Ndx); + Info.IsEnum = isArgEnum(Ndx, &Info.Enum); + Info.IsSampler = isArgSampler(Ndx); + Info.IsAtomic = isArgAtomic(Ndx); + Info.IsLocalArgBlock = isLocalArgBlock(Ndx); + Info.Attr = getArgAttr(Ndx); + return Info; + } + virtual void init(const std::string &UniqUnmangledName){ + UnmangledName = UniqUnmangledName; + } +protected: + std::string UnmangledName; + std::set<int> UnsignedArgs; // unsigned arguments, or -1 if all are unsigned + std::set<int> VoidPtrArgs; // void pointer arguments, or -1 if all are void + // pointer + std::set<int> SamplerArgs; // sampler arguments + std::set<int> AtomicArgs; // atomic arguments + std::map<int, SPIR::TypePrimitiveEnum> EnumArgs; // enum arguments + std::map<int, unsigned> Attrs; // argument attributes + int LocalArgBlockIdx; // index of a block with local arguments, idx < 0 if none + int VarArgIdx; // index of ellipsis argument, idx < 0 if none +}; + +/// \returns a vector of types for a collection of values. +template<class T> +std::vector<Type *> +getTypes(T V) { + std::vector<Type *> Tys; + for (auto &I:V) + Tys.push_back(I->getType()); + 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, + Attribute::AttrKind Attr); +void saveLLVMModule(Module *M, const std::string &OutputFile); +std::string mapSPIRVTypeToOCLType(SPIRVType* Ty, bool Signed); +std::string mapLLVMTypeToOCLType(const Type* Ty, bool Signed); +SPIRVDecorate *mapPostfixToDecorate(StringRef Postfix, SPIRVEntry *Target); + +/// Add decorations to a SPIR-V entry. +/// \param Decs Each string is a postfix without _ at the beginning. +SPIRVValue *addDecorations(SPIRVValue *Target, + const SmallVectorImpl<std::string>& Decs); + +PointerType *getOrCreateOpaquePtrType(Module *M, const std::string &Name, + unsigned AddrSpace = SPIRAS_Global); +PointerType* getSamplerType(Module *M); +PointerType* getPipeStorageType(Module *M); +void getFunctionTypeParameterTypes(llvm::FunctionType* FT, + std::vector<Type*>& ArgTys); +Function *getOrCreateFunction(Module *M, Type *RetTy, + ArrayRef<Type *> ArgTypes, StringRef Name, + BuiltinFuncMangleInfo *Mangle = nullptr, + AttributeList *Attrs = nullptr, bool takeName = true); + +/// Get function call arguments. +/// \param Start Starting index. +/// \param End Ending index. +std::vector<Value *> getArguments(CallInst* CI, unsigned Start = 0, + unsigned End = 0); + +/// Get constant function call argument as an integer. +/// \param I argument index. +uint64_t getArgAsInt(CallInst *CI, unsigned I); + +/// Get constant function call argument as type \param T. +/// \param I argument index. +template<typename T> +T getArgAs(CallInst *CI, unsigned I){ + return static_cast<T>(getArgAsInt(CI, I)); +} + +/// Get constant function call argument as a Scope enum. +/// \param I argument index. +Scope getArgAsScope(CallInst *CI, unsigned I); + +/// Get constant function call argument as a Decoration enum. +/// \param I argument index. +Decoration getArgAsDecoration(CallInst *CI, unsigned I); + +bool isPointerToOpaqueStructType(llvm::Type* Ty); +bool isPointerToOpaqueStructType(llvm::Type* Ty, const std::string &Name); + +/// Check if a type is OCL image type. +/// \return type name without "opencl." prefix. +bool isOCLImageType(llvm::Type* Ty, StringRef *Name = nullptr); + +/// \param BaseTyName is the type name as in spirv.BaseTyName.Postfixes +/// \param Postfix contains postfixes extracted from the SPIR-V image +/// type name as spirv.BaseTyName.Postfixes. bool -isSPIRVConstantName(StringRef TyName);
-
-/// Get SPIR-V type by changing the type name from spirv.OldName.Postfixes
-/// to spirv.NewName.Postfixes.
-Type *
-getSPIRVTypeByChangeBaseTypeName(Module *M, Type *T, StringRef OldName,
- StringRef NewName);
-
-/// Get the postfixes of SPIR-V image type name as in spirv.Image.postfixes.
-std::string
-getSPIRVImageTypePostfixes(StringRef SampledType,
- SPIRVTypeImageDescriptor Desc,
- SPIRVAccessQualifierKind Acc);
-
-/// Get the sampled type name used in postfix of image type in SPIR-V
-/// friendly LLVM IR.
-std::string
-getSPIRVImageSampledTypeName(SPIRVType *Ty);
-
-/// Translates OpenCL image type names to SPIR-V.
-/// E.g. %opencl.image1d_rw_t -> %spirv.Image._void_0_0_0_0_0_0_2
-Type *getSPIRVImageTypeFromOCL(Module *M, Type *T);
-
-/// Get LLVM type for sampled type of SPIR-V image type by postfix.
-Type*
-getLLVMTypeForSPIRVImageSampledTypePostfix(StringRef Postfix,
- LLVMContext &Ctx);
-
-/// Map OpenCL opaque type name to SPIR-V type name.
-std::string
-mapOCLTypeNameToSPIRV(StringRef Name, StringRef Acc = "");
-
-/// Check if access qualifier is encoded in the type name.
-bool hasAccessQualifiedName(StringRef TyName);
-
-/// Get access qualifier from the type name.
-StringRef getAccessQualifier(StringRef TyName);
-
-bool
-eraseUselessFunctions(Module *M);
-
-/// Erase a function if it is declaration, has internal linkage and has no use.
-bool
-eraseIfNoUse(Function *F);
-
-void
-eraseIfNoUse(Value *V);
-
-// Check if a mangled type name is unsigned
-bool
-isMangledTypeUnsigned(char Mangled);
-
-// Check if a mangled type name is signed
-bool
-isMangledTypeSigned(char Mangled);
-
-// Check if a mangled type name is floating point (except half)
-bool
-isMangledTypeFP(char Mangled);
-
-// Check if a mangled type name is half
-bool
-isMangledTypeHalf(std::string Mangled);
-
-// Check if \param I is valid vector size: 2, 3, 4, 8, 16.
-bool
-isValidVectorSize(unsigned I);
-
-enum class ParamType
-{
- FLOAT = 0,
- SIGNED = 1,
- UNSIGNED = 2,
- UNKNOWN = 3
-};
-
-ParamType LastFuncParamType(const std::string& MangledName);
-
-// Check if the last function parameter is signed
-bool
-isLastFuncParamSigned(const std::string& MangledName);
-
-// Check if a mangled function name contains unsigned atomic type
-bool
-containsUnsignedAtomicType(StringRef Name);
-
-/// Mangle builtin function name.
-/// \return \param UniqName if \param BtnInfo is null pointer, otherwise
-/// return IA64 mangled name.
-std::string
-mangleBuiltin(const std::string &UniqName,
- ArrayRef<Type*> ArgTypes, BuiltinFuncMangleInfo* BtnInfo);
-
-/// Remove cast from a value.
-Value *
-removeCast(Value *V);
-
-/// Cast a function to a void(void) funtion pointer.
-Constant *
-castToVoidFuncPtr(Function *F);
-
-/// Get i8* with the same address space.
-PointerType *getInt8PtrTy(PointerType *T);
-
-/// Cast a value to a i8* by inserting a cast instruction.
-Value *
-castToInt8Ptr(Value *V, Instruction *Pos);
-
-template<> inline void
-SPIRVMap<std::string, Op, SPIRVOpaqueType>::init() {
- add(kSPIRVTypeName::DeviceEvent, OpTypeDeviceEvent);
- add(kSPIRVTypeName::Event, OpTypeEvent);
- add(kSPIRVTypeName::Image, OpTypeImage);
- add(kSPIRVTypeName::Pipe, OpTypePipe);
- add(kSPIRVTypeName::Queue, OpTypeQueue);
- add(kSPIRVTypeName::ReserveId, OpTypeReserveId);
- add(kSPIRVTypeName::Sampler, OpTypeSampler);
- add(kSPIRVTypeName::SampledImg, OpTypeSampledImage);
-}
-
-}
-
-#endif
+isSPIRVType(llvm::Type* Ty, StringRef BaseTyName, StringRef *Postfix = 0); + +/// Decorate a function name as __spirv_{Name}_ +std::string decorateSPIRVFunction(const std::string &S); + +/// Remove prefix/postfix from __spirv_{Name}_ +std::string undecorateSPIRVFunction(const std::string &S); + +/// Check if a function has decorated name as __spirv_{Name}_ +/// and get the original name. +bool isDecoratedSPIRVFunc(const Function *F, std::string *UndecName = nullptr); + +/// Get a canonical function name for a SPIR-V op code. +std::string getSPIRVFuncName(Op OC, StringRef PostFix = ""); + +std::string getSPIRVFuncName(Op OC, const Type *pRetTy, bool IsSigned = false); + +/// Get a canonical function name for a SPIR-V extended instruction +std::string getSPIRVExtFuncName(SPIRVExtInstSetKind Set, unsigned ExtOp, + StringRef PostFix = ""); + +/// Get SPIR-V op code given the canonical function name. +/// Assume \param Name is either IA64 mangled or unmangled, and the unmangled +/// name takes the __spirv_{OpName}_{Postfixes} format. +/// \return op code if the unmangled function name is a valid op code name, +/// otherwise return OpNop. +/// \param Dec contains decorations decoded from function name if it is +/// not nullptr. +Op getSPIRVFuncOC(const std::string& Name, + SmallVectorImpl<std::string> *Dec = nullptr); + +/// Get SPIR-V builtin variable enum given the canonical builtin name +/// Assume \param Name is in format __spirv_BuiltIn{Name} +/// \return false if \param Name is not a valid builtin name. +bool getSPIRVBuiltin(const std::string &Name, spv::BuiltIn &Builtin); + +/// \param Name LLVM function name +/// \param DemangledName demanged name of the OpenCL built-in function +/// \returns true if Name is the name of the OpenCL built-in function, +/// false for other functions +bool oclIsBuiltin(const StringRef &Name, std::string *DemangledName = nullptr, + bool isCPP = false); + +/// Check if a function type is void(void). +bool isVoidFuncTy(FunctionType *FT); + +/// \returns true if \p T is a function pointer type. +bool isFunctionPointerType(Type *T); + +/// \returns true if function \p F has function pointer type argument. +/// \param AI points to the function pointer type argument if returns true. +bool hasFunctionPointerArg(Function *F, Function::arg_iterator& AI); + +/// \returns true if function \p F has array type argument. +bool hasArrayArg(Function *F); + +/// Mutates function call instruction by changing the arguments. +/// \param ArgMutate mutates the function arguments. +/// \return mutated call instruction. +CallInst *mutateCallInst(Module *M, CallInst *CI, + std::function<std::string (CallInst *, std::vector<Value *> &)>ArgMutate, + BuiltinFuncMangleInfo *Mangle = nullptr, AttributeList *Attrs = nullptr, + bool takeName = false); + +/// Mutates function call instruction by changing the arguments and return +/// value. +/// \param ArgMutate mutates the function arguments. +/// \param RetMutate mutates the return value. +/// \return mutated instruction. +Instruction *mutateCallInst(Module *M, CallInst *CI, + std::function<std::string (CallInst *, std::vector<Value *> &, + Type *&RetTy)> ArgMutate, + std::function<Instruction *(CallInst *)> RetMutate, + BuiltinFuncMangleInfo *Mangle = nullptr, AttributeList *Attrs = nullptr, + bool takeName = false); + +/// Mutate call instruction to call SPIR-V builtin function. +CallInst * +mutateCallInstSPIRV(Module *M, CallInst *CI, + std::function<std::string (CallInst *, std::vector<Value *> &)>ArgMutate, + AttributeList *Attrs = nullptr); + +/// Mutate call instruction to call SPIR-V builtin function. +Instruction * +mutateCallInstSPIRV(Module *M, CallInst *CI, + std::function<std::string (CallInst *, std::vector<Value *> &, + Type *&RetTy)> ArgMutate, + std::function<Instruction *(CallInst *)> RetMutate, + AttributeList *Attrs = nullptr); + +/// Mutate function by change the arguments. +/// \param ArgMutate mutates the function arguments. +/// \param TakeName Take the original function's name if a new function with +/// different type needs to be created. +void mutateFunction(Function *F, + std::function<std::string (CallInst *, std::vector<Value *> &)>ArgMutate, + BuiltinFuncMangleInfo *Mangle = nullptr, AttributeList *Attrs = nullptr, + bool TakeName = true); + +/// Add a call instruction at \p Pos. +CallInst *addCallInst(Module *M, StringRef FuncName, Type *RetTy, + ArrayRef<Value *> Args, AttributeList *Attrs, Instruction *Pos, + BuiltinFuncMangleInfo *Mangle = nullptr, + StringRef InstName = SPIR_TEMP_NAME_PREFIX_CALL, + bool TakeFuncName = true); + +/// Add a call instruction for SPIR-V builtin function. +CallInst * +addCallInstSPIRV(Module *M, StringRef FuncName, Type *RetTy, + ArrayRef<Value *> Args, + AttributeList *Attrs, Instruction *Pos, StringRef InstName); + +/// Add a call of spir_block_bind function. +CallInst * +addBlockBind(Module *M, Function *InvokeFunc, Value *BlkCtx, Value *CtxLen, + Value *CtxAlign, Instruction *InsPos, + StringRef InstName = SPIR_TEMP_NAME_PREFIX_BLOCK); + +typedef std::pair<std::vector<Value *>::iterator, + std::vector<Value *>::iterator> ValueVecRange; + +/// Add a vector at \param InsPos. +Value * +addVector(Instruction *InsPos, ValueVecRange Range); + +/// Replace scalar values with a vector created at \param InsPos. +void +makeVector(Instruction *InsPos, std::vector<Value *> &Ops, + ValueVecRange Range); + +/// Expand a vector type value in \param Ops at index \param VecPos. +/// Generate extract element instructions at \param InsPos and replace +/// the vector type value with scalar type values. +/// If the value to be expanded is not vector type, do nothing. +void +expandVector(Instruction *InsPos, std::vector<Value *> &Ops, size_t VecPos); + +/// Get size_t type. +IntegerType *getSizetType(Module *M); + +/// Get void(void) function type. +Type *getVoidFuncType(Module *M); + +/// Get void(void) function pointer type. +Type *getVoidFuncPtrType(Module *M, unsigned AddrSpace = 0); + +/// Get a 64 bit integer constant. +ConstantInt *getInt64(Module *M, int64_t value); + +/// Get a 32 bit integer constant. +ConstantInt *getInt32(Module *M, int value); + +/// Get a 32 bit unsigned integer constant. +ConstantInt *getUInt32(Module *M, unsigned value); + +/// Get a 16 bit unsigned integer constant. +ConstantInt *getUInt16(Module *M, unsigned short value); + +// Get a 32 bit floating point constant. +Constant *getFloat32(Module *M, float value); + +/// Get a 32 bit integer constant vector. +std::vector<Value *> getInt32(Module *M, const std::vector<int> &value); + +/// Get a size_t type constant. +ConstantInt *getSizet(Module *M, uint64_t value); + +/// 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 a named metadata as a set of string. +/// Assume the named metadata has one or more operands each of which might +/// contain set of strings. For instance: +/// !opencl.used.optional.core.features = !{!0} +/// !0 = !{!"cl_doubles", !"cl_images"} +/// or if we linked two modules we may have +/// !opencl.used.optional.core.features = !{!0, !1} +/// !0 = !{!"cl_doubles"} +/// !1 = !{!"cl_images"} +std::set<std::string> getNamedMDAsStringSet(Module *M, + const std::string &MDName); + +/// Get SPIR-V language by SPIR-V metadata spirv.Source +std::tuple<unsigned, unsigned, std::string> +getSPIRVSource(Module *M); + +/// 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); + +/// Get postfix for given decoration. +/// The returned postfix does not include "_" at the beginning. +std::string getPostfix(Decoration Dec, unsigned Value = 0); + +/// Get postfix _R{ReturnType} for return type +/// The returned postfix does not includ "_" at the beginning +std::string getPostfixForReturnType(CallInst *CI, bool IsSigned = false); +std::string getPostfixForReturnType(const Type *pRetTy, bool IsSigned = false); + +Constant * +getScalarOrVectorConstantInt(Type *T, uint64_t V, bool isSigned = false); + +/// Get a constant int or a constant int array. +/// \param T is the type of the constant. It should be an integer type or +// an integer pointer type. +/// \param Len is the length of the array. +/// \param V is the value to fill the array. +Value * +getScalarOrArrayConstantInt(Instruction *P, Type *T, unsigned Len, uint64_t V, + bool isSigned = false); + +/// Get the array from GEP. +/// \param V is a GEP whose pointer operand is a pointer to an array of size +/// \param Size. +Value * +getScalarOrArray(Value *V, unsigned Size, Instruction *Pos); + +void +dumpUsers(Value* V, StringRef Prompt = ""); + +/// Get SPIR-V type name as spirv.BaseTyName.Postfixes. +std::string +getSPIRVTypeName(StringRef BaseTyName, StringRef Postfixes = ""); + +/// Checks if given type name is either ConstantSampler or ConsantPipeStorage. +bool +isSPIRVConstantName(StringRef TyName); + +/// Get SPIR-V type by changing the type name from spirv.OldName.Postfixes +/// to spirv.NewName.Postfixes. +Type * +getSPIRVTypeByChangeBaseTypeName(Module *M, Type *T, StringRef OldName, + StringRef NewName); + +/// Get the postfixes of SPIR-V image type name as in spirv.Image.postfixes. +std::string +getSPIRVImageTypePostfixes(StringRef SampledType, + SPIRVTypeImageDescriptor Desc, + SPIRVAccessQualifierKind Acc); + +/// Get the sampled type name used in postfix of image type in SPIR-V +/// friendly LLVM IR. +std::string +getSPIRVImageSampledTypeName(SPIRVType *Ty); + +/// Translates OpenCL image type names to SPIR-V. +/// E.g. %opencl.image1d_rw_t -> %spirv.Image._void_0_0_0_0_0_0_2 +Type *getSPIRVImageTypeFromOCL(Module *M, Type *T); + +/// Get LLVM type for sampled type of SPIR-V image type by postfix. +Type* +getLLVMTypeForSPIRVImageSampledTypePostfix(StringRef Postfix, + LLVMContext &Ctx); + +/// Map OpenCL opaque type name to SPIR-V type name. +std::string +mapOCLTypeNameToSPIRV(StringRef Name, StringRef Acc = ""); + +/// Check if access qualifier is encoded in the type name. +bool hasAccessQualifiedName(StringRef TyName); + +/// Get access qualifier from the type name. +StringRef getAccessQualifier(StringRef TyName); + +bool +eraseUselessFunctions(Module *M); + +/// Erase a function if it is declaration, has internal linkage and has no use. +bool +eraseIfNoUse(Function *F); + +void +eraseIfNoUse(Value *V); + +// Check if a mangled type name is unsigned +bool +isMangledTypeUnsigned(char Mangled); + +// Check if a mangled type name is signed +bool +isMangledTypeSigned(char Mangled); + +// Check if a mangled type name is floating point (except half) +bool +isMangledTypeFP(char Mangled); + +// Check if a mangled type name is half +bool +isMangledTypeHalf(std::string Mangled); + +// Check if \param I is valid vector size: 2, 3, 4, 8, 16. +bool +isValidVectorSize(unsigned I); + +enum class ParamType +{ + FLOAT = 0, + SIGNED = 1, + UNSIGNED = 2, + UNKNOWN = 3 +}; + +ParamType LastFuncParamType(const std::string& MangledName); + +// Check if the last function parameter is signed +bool +isLastFuncParamSigned(const std::string& MangledName); + +// Check if a mangled function name contains unsigned atomic type +bool +containsUnsignedAtomicType(StringRef Name); + +/// Mangle builtin function name. +/// \return \param UniqName if \param BtnInfo is null pointer, otherwise +/// return IA64 mangled name. +std::string +mangleBuiltin(const std::string &UniqName, + ArrayRef<Type*> ArgTypes, BuiltinFuncMangleInfo* BtnInfo); + +/// Remove cast from a value. +Value * +removeCast(Value *V); + +/// Cast a function to a void(void) funtion pointer. +Constant * +castToVoidFuncPtr(Function *F); + +/// Get i8* with the same address space. +PointerType *getInt8PtrTy(PointerType *T); + +/// Cast a value to a i8* by inserting a cast instruction. +Value * +castToInt8Ptr(Value *V, Instruction *Pos); + +template<> inline void +SPIRVMap<std::string, Op, SPIRVOpaqueType>::init() { + add(kSPIRVTypeName::DeviceEvent, OpTypeDeviceEvent); + add(kSPIRVTypeName::Event, OpTypeEvent); + add(kSPIRVTypeName::Image, OpTypeImage); + add(kSPIRVTypeName::Pipe, OpTypePipe); + add(kSPIRVTypeName::Queue, OpTypeQueue); + add(kSPIRVTypeName::ReserveId, OpTypeReserveId); + add(kSPIRVTypeName::Sampler, OpTypeSampler); + add(kSPIRVTypeName::SampledImg, OpTypeSampledImage); +} + +} + +#endif diff --git a/lib/SPIRV/SPIRVLowerBool.cpp b/lib/SPIRV/SPIRVLowerBool.cpp index fb3f454..08cd848 100644 --- a/lib/SPIRV/SPIRVLowerBool.cpp +++ b/lib/SPIRV/SPIRVLowerBool.cpp @@ -1,134 +1,134 @@ -//===- SPIRVLowerBool.cpp – Lower instructions with bool operands ----------===//
-//
-// 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 lowering instructions with bool operands.
-//
-//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "spvbool"
-
-#include "SPIRVInternal.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/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace llvm;
-using namespace SPIRV;
-
-namespace SPIRV {
-cl::opt<bool> SPIRVLowerBoolValidate("spvbool-validate",
- cl::desc("Validate module after lowering boolean instructions for SPIR-V"));
-
-class SPIRVLowerBool: public ModulePass,
- public InstVisitor<SPIRVLowerBool> {
-public:
- SPIRVLowerBool():ModulePass(ID), Context(nullptr) {
- initializeSPIRVLowerBoolPass(*PassRegistry::getPassRegistry());
- }
- void replace(Instruction *I, Instruction *NewI) {
- NewI->takeName(I);
- I->replaceAllUsesWith(NewI);
- I->dropAllReferences();
- I->eraseFromParent();
- }
- bool isBoolType(Type *Ty) {
- if (Ty->isIntegerTy(1))
- return true;
- if (auto VT = dyn_cast<VectorType>(Ty))
- return isBoolType(VT->getElementType());
- return false;
- }
- virtual void visitTruncInst(TruncInst &I) {
- if (isBoolType(I.getType())) {
- auto Op = I.getOperand(0);
- auto Zero = getScalarOrVectorConstantInt(Op->getType(), 0, false);
- auto Cmp = new ICmpInst(&I, CmpInst::ICMP_NE, Op, Zero);
- replace(&I, Cmp);
- }
- }
- virtual void visitZExtInst(ZExtInst &I) {
- auto Op = I.getOperand(0);
- if (isBoolType(Op->getType())) {
- auto Ty = I.getType();
- auto Zero = getScalarOrVectorConstantInt(Ty, 0, false);
- auto One = getScalarOrVectorConstantInt(Ty, 1, false);
- auto Sel = SelectInst::Create(Op, One, Zero, "", &I);
- replace(&I, Sel);
- }
- }
- virtual void visitSExtInst(SExtInst &I) {
- auto Op = I.getOperand(0);
- if (isBoolType(Op->getType())) {
- auto Ty = I.getType();
- auto Zero = getScalarOrVectorConstantInt(Ty, 0, false);
- auto One = getScalarOrVectorConstantInt(Ty, ~0, false);
- auto Sel = SelectInst::Create(Op, One, Zero, "", &I);
- replace(&I, Sel);
- }
- }
- virtual bool runOnModule(Module &M) {
- Context = &M.getContext();
- visit(M);
-
- if (SPIRVLowerBoolValidate) {
- DEBUG(dbgs() << "After SPIRVLowerBool:\n" << M);
- std::string Err;
- raw_string_ostream ErrorOS(Err);
- if (verifyModule(M, &ErrorOS)){
- Err = std::string("Fails to verify module: ") + Err;
- report_fatal_error(Err.c_str(), false);
- }
- }
- return true;
- }
-
- static char ID;
-private:
- LLVMContext *Context;
-};
-
-char SPIRVLowerBool::ID = 0;
-}
-
-INITIALIZE_PASS(SPIRVLowerBool, "spvbool",
- "Lower instructions with bool operands", false, false)
-
-ModulePass *llvm::createSPIRVLowerBool() {
- return new SPIRVLowerBool();
-}
+//===- SPIRVLowerBool.cpp – Lower instructions with bool operands ----------===// +// +// 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 lowering instructions with bool operands. +// +//===----------------------------------------------------------------------===// +#define DEBUG_TYPE "spvbool" + +#include "SPIRVInternal.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/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace SPIRV; + +namespace SPIRV { +cl::opt<bool> SPIRVLowerBoolValidate("spvbool-validate", + cl::desc("Validate module after lowering boolean instructions for SPIR-V")); + +class SPIRVLowerBool: public ModulePass, + public InstVisitor<SPIRVLowerBool> { +public: + SPIRVLowerBool():ModulePass(ID), Context(nullptr) { + initializeSPIRVLowerBoolPass(*PassRegistry::getPassRegistry()); + } + void replace(Instruction *I, Instruction *NewI) { + NewI->takeName(I); + I->replaceAllUsesWith(NewI); + I->dropAllReferences(); + I->eraseFromParent(); + } + bool isBoolType(Type *Ty) { + if (Ty->isIntegerTy(1)) + return true; + if (auto VT = dyn_cast<VectorType>(Ty)) + return isBoolType(VT->getElementType()); + return false; + } + virtual void visitTruncInst(TruncInst &I) { + if (isBoolType(I.getType())) { + auto Op = I.getOperand(0); + auto Zero = getScalarOrVectorConstantInt(Op->getType(), 0, false); + auto Cmp = new ICmpInst(&I, CmpInst::ICMP_NE, Op, Zero); + replace(&I, Cmp); + } + } + virtual void visitZExtInst(ZExtInst &I) { + auto Op = I.getOperand(0); + if (isBoolType(Op->getType())) { + auto Ty = I.getType(); + auto Zero = getScalarOrVectorConstantInt(Ty, 0, false); + auto One = getScalarOrVectorConstantInt(Ty, 1, false); + auto Sel = SelectInst::Create(Op, One, Zero, "", &I); + replace(&I, Sel); + } + } + virtual void visitSExtInst(SExtInst &I) { + auto Op = I.getOperand(0); + if (isBoolType(Op->getType())) { + auto Ty = I.getType(); + auto Zero = getScalarOrVectorConstantInt(Ty, 0, false); + auto One = getScalarOrVectorConstantInt(Ty, ~0, false); + auto Sel = SelectInst::Create(Op, One, Zero, "", &I); + replace(&I, Sel); + } + } + virtual bool runOnModule(Module &M) { + Context = &M.getContext(); + visit(M); + + if (SPIRVLowerBoolValidate) { + DEBUG(dbgs() << "After SPIRVLowerBool:\n" << M); + std::string Err; + raw_string_ostream ErrorOS(Err); + if (verifyModule(M, &ErrorOS)){ + Err = std::string("Fails to verify module: ") + Err; + report_fatal_error(Err.c_str(), false); + } + } + return true; + } + + static char ID; +private: + LLVMContext *Context; +}; + +char SPIRVLowerBool::ID = 0; +} + +INITIALIZE_PASS(SPIRVLowerBool, "spvbool", + "Lower instructions with bool operands", false, false) + +ModulePass *llvm::createSPIRVLowerBool() { + return new SPIRVLowerBool(); +} diff --git a/lib/SPIRV/SPIRVLowerMemmove.cpp b/lib/SPIRV/SPIRVLowerMemmove.cpp index ff269d6..06bf8cf 100644 --- a/lib/SPIRV/SPIRVLowerMemmove.cpp +++ b/lib/SPIRV/SPIRVLowerMemmove.cpp @@ -1,140 +1,140 @@ -//===- SPIRVLowerMemmove.cpp - Lower llvm.memmove to llvm.memcpys ----------===//
-//
-// 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 lowering llvm.memmove into several llvm.memcpys.
-//
-//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "spvmemmove"
-
-#include "SPIRVInternal.h"
-#include "llvm/IR/InstVisitor.h"
-#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/Pass.h"
-#include "llvm/PassSupport.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace llvm;
-using namespace SPIRV;
-
-namespace SPIRV {
-cl::opt<bool> SPIRVLowerMemmoveValidate("spvmemmove-validate",
- cl::desc("Validate module after lowering llvm.memmove instructions into "
- "llvm.memcpy"));
-
-class SPIRVLowerMemmove: public ModulePass,
- public InstVisitor<SPIRVLowerMemmove> {
-public:
- SPIRVLowerMemmove():ModulePass(ID), Context(nullptr) {
- initializeSPIRVLowerMemmovePass(*PassRegistry::getPassRegistry());
- }
- virtual void visitMemMoveInst(MemMoveInst &I) {
- IRBuilder<> Builder(I.getParent());
- Builder.SetInsertPoint(&I);
- auto *Dest = I.getRawDest();
- auto *Src = I.getRawSource();
- auto *SrcTy = Src->getType();
- if (!isa<ConstantInt>(I.getLength()))
- // ToDo: for non-constant length, could use a loop to copy a
- // fixed length chunk at a time. For now simply fail
- report_fatal_error("llvm.memmove of non-constant length not supported",
- false);
- auto *Length = cast<ConstantInt>(I.getLength());
- if (isa<BitCastInst>(Src))
- // The source could be bit-cast from another type,
- // need the original type for the allocation of the temporary variable
- SrcTy = cast<BitCastInst>(Src)->getOperand(0)->getType();
- auto Align = I.getSourceAlignment();
- auto Volatile = I.isVolatile();
- Value *NumElements = nullptr;
- uint64_t ElementsCount = 1;
- if (SrcTy->isArrayTy()) {
- NumElements = Builder.getInt32(SrcTy->getArrayNumElements());
- ElementsCount = SrcTy->getArrayNumElements();
- }
- if (Mod->getDataLayout().getTypeSizeInBits(SrcTy->getPointerElementType())
- * ElementsCount != Length->getZExtValue() * 8)
- report_fatal_error("Size of the memcpy should match the allocated memory",
- false);
-
- auto *Alloca = Builder.CreateAlloca(SrcTy->getPointerElementType(),
- NumElements);
- Alloca->setAlignment(Align);
- Builder.CreateLifetimeStart(Alloca);
- Builder.CreateMemCpy(Alloca, Align, Src, Align, Length, Volatile);
- auto *SecondCpy = Builder.CreateMemCpy(Dest, I.getDestAlignment(), Alloca,
- Align, Length, Volatile);
- Builder.CreateLifetimeEnd(Alloca);
-
- SecondCpy->takeName(&I);
- I.replaceAllUsesWith(SecondCpy);
- I.dropAllReferences();
- I.eraseFromParent();
- }
- virtual bool runOnModule(Module &M) {
- Context = &M.getContext();
- Mod = &M;
- visit(M);
-
- if (SPIRVLowerMemmoveValidate) {
- DEBUG(dbgs() << "After SPIRVLowerMemmove:\n" << M);
- std::string Err;
- raw_string_ostream ErrorOS(Err);
- if (verifyModule(M, &ErrorOS)){
- Err = std::string("Fails to verify module: ") + Err;
- report_fatal_error(Err.c_str(), false);
- }
- }
- return true;
- }
-
- static char ID;
-private:
- LLVMContext *Context;
- Module *Mod;
-};
-
-char SPIRVLowerMemmove::ID = 0;
-}
-
-INITIALIZE_PASS(SPIRVLowerMemmove, "spvmemmove",
- "Lower llvm.memmove into llvm.memcpy", false, false)
-
-ModulePass *llvm::createSPIRVLowerMemmove() {
- return new SPIRVLowerMemmove();
-}
+//===- SPIRVLowerMemmove.cpp - Lower llvm.memmove to llvm.memcpys ----------===// +// +// 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 lowering llvm.memmove into several llvm.memcpys. +// +//===----------------------------------------------------------------------===// +#define DEBUG_TYPE "spvmemmove" + +#include "SPIRVInternal.h" +#include "llvm/IR/InstVisitor.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Pass.h" +#include "llvm/PassSupport.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace SPIRV; + +namespace SPIRV { +cl::opt<bool> SPIRVLowerMemmoveValidate("spvmemmove-validate", + cl::desc("Validate module after lowering llvm.memmove instructions into " + "llvm.memcpy")); + +class SPIRVLowerMemmove: public ModulePass, + public InstVisitor<SPIRVLowerMemmove> { +public: + SPIRVLowerMemmove():ModulePass(ID), Context(nullptr) { + initializeSPIRVLowerMemmovePass(*PassRegistry::getPassRegistry()); + } + virtual void visitMemMoveInst(MemMoveInst &I) { + IRBuilder<> Builder(I.getParent()); + Builder.SetInsertPoint(&I); + auto *Dest = I.getRawDest(); + auto *Src = I.getRawSource(); + auto *SrcTy = Src->getType(); + if (!isa<ConstantInt>(I.getLength())) + // ToDo: for non-constant length, could use a loop to copy a + // fixed length chunk at a time. For now simply fail + report_fatal_error("llvm.memmove of non-constant length not supported", + false); + auto *Length = cast<ConstantInt>(I.getLength()); + if (isa<BitCastInst>(Src)) + // The source could be bit-cast from another type, + // need the original type for the allocation of the temporary variable + SrcTy = cast<BitCastInst>(Src)->getOperand(0)->getType(); + auto Align = I.getSourceAlignment(); + auto Volatile = I.isVolatile(); + Value *NumElements = nullptr; + uint64_t ElementsCount = 1; + if (SrcTy->isArrayTy()) { + NumElements = Builder.getInt32(SrcTy->getArrayNumElements()); + ElementsCount = SrcTy->getArrayNumElements(); + } + if (Mod->getDataLayout().getTypeSizeInBits(SrcTy->getPointerElementType()) + * ElementsCount != Length->getZExtValue() * 8) + report_fatal_error("Size of the memcpy should match the allocated memory", + false); + + auto *Alloca = Builder.CreateAlloca(SrcTy->getPointerElementType(), + NumElements); + Alloca->setAlignment(Align); + Builder.CreateLifetimeStart(Alloca); + Builder.CreateMemCpy(Alloca, Align, Src, Align, Length, Volatile); + auto *SecondCpy = Builder.CreateMemCpy(Dest, I.getDestAlignment(), Alloca, + Align, Length, Volatile); + Builder.CreateLifetimeEnd(Alloca); + + SecondCpy->takeName(&I); + I.replaceAllUsesWith(SecondCpy); + I.dropAllReferences(); + I.eraseFromParent(); + } + virtual bool runOnModule(Module &M) { + Context = &M.getContext(); + Mod = &M; + visit(M); + + if (SPIRVLowerMemmoveValidate) { + DEBUG(dbgs() << "After SPIRVLowerMemmove:\n" << M); + std::string Err; + raw_string_ostream ErrorOS(Err); + if (verifyModule(M, &ErrorOS)){ + Err = std::string("Fails to verify module: ") + Err; + report_fatal_error(Err.c_str(), false); + } + } + return true; + } + + static char ID; +private: + LLVMContext *Context; + Module *Mod; +}; + +char SPIRVLowerMemmove::ID = 0; +} + +INITIALIZE_PASS(SPIRVLowerMemmove, "spvmemmove", + "Lower llvm.memmove into llvm.memcpy", false, false) + +ModulePass *llvm::createSPIRVLowerMemmove() { + return new SPIRVLowerMemmove(); +} diff --git a/lib/SPIRV/SPIRVLowerOCLBlocks.cpp b/lib/SPIRV/SPIRVLowerOCLBlocks.cpp index 55fea33..668c2ad 100644 --- a/lib/SPIRV/SPIRVLowerOCLBlocks.cpp +++ b/lib/SPIRV/SPIRVLowerOCLBlocks.cpp @@ -1,636 +1,636 @@ -//===- SPIRVLowerOCLBlocks.cpp - Lower OpenCL blocks ------------*- C++ -*-===//
-//
-// The LLVM/SPIR-V 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file implements lowering of OpenCL blocks to functions.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef OCLLOWERBLOCKS_H_
-#define OCLLOWERBLOCKS_H_
-
-#include "SPIRVInternal.h"
-#include "OCLUtil.h"
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SetVector.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Analysis/AliasAnalysis.h"
-#include "llvm/Analysis/AssumptionCache.h"
-#include "llvm/Analysis/CallGraph.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/Bitcode/BitcodeWriter.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/InstrTypes.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Operator.h"
-#include "llvm/Pass.h"
-#include "llvm/PassSupport.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Transforms/Utils/Cloning.h"
-#include "llvm/Transforms/Utils/GlobalStatus.h"
-#include <iostream>
-#include <list>
-#include <memory>
-#include <set>
-#include <sstream>
-#include <vector>
-
-#define DEBUG_TYPE "spvblocks"
-
-using namespace llvm;
-using namespace SPIRV;
-using namespace OCLUtil;
-
-namespace SPIRV{
-
-/// Lower SPIR2 blocks to function calls.
-///
-/// SPIR2 representation of blocks:
-///
-/// block = spir_block_bind(bitcast(block_func), context_len, context_align,
-/// context)
-/// block_func_ptr = bitcast(spir_get_block_invoke(block))
-/// context_ptr = spir_get_block_context(block)
-/// ret = block_func_ptr(context_ptr, args)
-///
-/// Propagates block_func to each spir_get_block_invoke through def-use chain of
-/// spir_block_bind, so that
-/// ret = block_func(context, args)
-class SPIRVLowerOCLBlocks: public ModulePass {
-public:
- SPIRVLowerOCLBlocks():ModulePass(ID), M(nullptr){
- initializeSPIRVLowerOCLBlocksPass(*PassRegistry::getPassRegistry());
- }
-
- virtual void getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<CallGraphWrapperPass>();
- AU.addRequired<AAResultsWrapperPass>();
- AU.addRequired<AssumptionCacheTracker>();
- }
-
- virtual bool runOnModule(Module &Module) {
- M = &Module;
- lowerBlockBind();
- lowerGetBlockInvoke();
- lowerGetBlockContext();
- EraseUselessGlobalVars();
- EliminateDeadArgs();
- erase(M->getFunction(SPIR_INTRINSIC_GET_BLOCK_INVOKE));
- erase(M->getFunction(SPIR_INTRINSIC_GET_BLOCK_CONTEXT));
- erase(M->getFunction(SPIR_INTRINSIC_BLOCK_BIND));
- DEBUG(dbgs() << "------- After OCLLowerBlocks ------------\n" <<
- *M << '\n');
- return true;
- }
-
- static char ID;
-private:
- const static int MaxIter = 1000;
- Module *M;
-
- bool
- lowerBlockBind() {
- auto F = M->getFunction(SPIR_INTRINSIC_BLOCK_BIND);
- if (!F)
- return false;
- int Iter = MaxIter;
- while(lowerBlockBind(F) && Iter > 0){
- Iter--;
- DEBUG(dbgs() << "-------------- after iteration " << MaxIter - Iter <<
- " --------------\n" << *M << '\n');
- }
- assert(Iter > 0 && "Too many iterations");
- return true;
- }
-
- bool
- eraseUselessFunctions() {
- bool changed = false;
- for (auto I = M->begin(), E = M->end(); I != E;) {
- Function *F = &(*I++);
- if (!GlobalValue::isInternalLinkage(F->getLinkage()) &&
- !F->isDeclaration())
- continue;
-
- dumpUsers(F, "[eraseUselessFunctions] ");
- for (auto UI = F->user_begin(), UE = F->user_end(); UI != UE;) {
- auto U = *UI++;
- if (auto CE = dyn_cast<ConstantExpr>(U)){
- if (CE->use_empty()) {
- CE->dropAllReferences();
- changed = true;
- }
- }
- }
-
- if (!F->use_empty()) {
- continue;
- }
-
- auto &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
- CallGraphNode* CGN = CG[F];
-
- if (CGN->getNumReferences() != 0) {
- continue;
- }
-
- erase(F);
- changed = true;
- }
- return changed;
- }
-
- void
- lowerGetBlockInvoke() {
- if (auto F = M->getFunction(SPIR_INTRINSIC_GET_BLOCK_INVOKE)) {
- for (auto UI = F->user_begin(), UE = F->user_end(); UI != UE;) {
- auto CI = dyn_cast<CallInst>(*UI++);
- assert(CI && "Invalid usage of spir_get_block_invoke");
- lowerGetBlockInvoke(CI);
- }
- }
- }
-
- void
- lowerGetBlockContext() {
- if (auto F = M->getFunction(SPIR_INTRINSIC_GET_BLOCK_CONTEXT)) {
- for (auto UI = F->user_begin(), UE = F->user_end(); UI != UE;) {
- auto CI = dyn_cast<CallInst>(*UI++);
- assert(CI && "Invalid usage of spir_get_block_context");
- lowerGetBlockContext(CI);
- }
- }
- }
- /// Lower calls of spir_block_bind.
- /// Return true if the Module is changed.
- bool
- lowerBlockBind(Function *BlockBindFunc) {
- bool changed = false;
- for (auto I = BlockBindFunc->user_begin(), E = BlockBindFunc->user_end();
- I != E;) {
- DEBUG(dbgs() << "[lowerBlockBind] " << **I << '\n');
- // Handle spir_block_bind(bitcast(block_func), context_len,
- // context_align, context)
- auto CallBlkBind = cast<CallInst>(*I++);
- Function *InvF = nullptr;
- Value *Ctx = nullptr;
- Value *CtxLen = nullptr;
- Value *CtxAlign = nullptr;
- getBlockInvokeFuncAndContext(CallBlkBind, &InvF, &Ctx, &CtxLen,
- &CtxAlign);
- for (auto II = CallBlkBind->user_begin(), EE = CallBlkBind->user_end();
- II != EE;) {
- auto BlkUser = *II++;
- SPIRVDBG(dbgs() << " Block user: " << *BlkUser << '\n');
- if (auto Ret = dyn_cast<ReturnInst>(BlkUser)) {
- bool Inlined = false;
- changed |= lowerReturnBlock(Ret, CallBlkBind, Inlined);
- if (Inlined)
- return true;
- } else if (auto CI = dyn_cast<CallInst>(BlkUser)){
- auto CallBindF = CI->getCalledFunction();
- auto Name = CallBindF->getName();
- std::string DemangledName;
- if (Name == SPIR_INTRINSIC_GET_BLOCK_INVOKE) {
- assert(CI->getArgOperand(0) == CallBlkBind);
- changed |= lowerGetBlockInvoke(CI, cast<Function>(InvF));
- } else if (Name == SPIR_INTRINSIC_GET_BLOCK_CONTEXT) {
- assert(CI->getArgOperand(0) == CallBlkBind);
- // Handle context_ptr = spir_get_block_context(block)
- lowerGetBlockContext(CI, Ctx);
- changed = true;
- } else if (oclIsBuiltin(Name, &DemangledName)) {
- lowerBlockBuiltin(CI, InvF, Ctx, CtxLen, CtxAlign, DemangledName);
- changed = true;
- } else
- llvm_unreachable("Invalid block user");
- }
- }
- erase(CallBlkBind);
- }
- changed |= eraseUselessFunctions();
- return changed;
- }
-
- void
- lowerGetBlockContext(CallInst *CallGetBlkCtx, Value *Ctx = nullptr) {
- if (!Ctx)
- getBlockInvokeFuncAndContext(CallGetBlkCtx->getArgOperand(0), nullptr,
- &Ctx);
- CallGetBlkCtx->replaceAllUsesWith(Ctx);
- DEBUG(dbgs() << " [lowerGetBlockContext] " << *CallGetBlkCtx << " => " <<
- *Ctx << "\n\n");
- erase(CallGetBlkCtx);
- }
-
- bool
- lowerGetBlockInvoke(CallInst *CallGetBlkInvoke,
- Function *InvokeF = nullptr) {
- bool changed = false;
- for (auto UI = CallGetBlkInvoke->user_begin(),
- UE = CallGetBlkInvoke->user_end();
- UI != UE;) {
- // Handle block_func_ptr = bitcast(spir_get_block_invoke(block))
- auto CallInv = cast<Instruction>(*UI++);
- auto Cast = dyn_cast<BitCastInst>(CallInv);
- if (Cast)
- CallInv = dyn_cast<Instruction>(*CallInv->user_begin());
- DEBUG(dbgs() << "[lowerGetBlockInvoke] " << *CallInv);
- // Handle ret = block_func_ptr(context_ptr, args)
- auto CI = cast<CallInst>(CallInv);
- auto F = CI->getCalledValue();
- if (InvokeF == nullptr) {
- getBlockInvokeFuncAndContext(CallGetBlkInvoke->getArgOperand(0),
- &InvokeF, nullptr);
- assert(InvokeF);
- }
- assert(F->getType() == InvokeF->getType());
- CI->replaceUsesOfWith(F, InvokeF);
- DEBUG(dbgs() << " => " << *CI << "\n\n");
- erase(Cast);
- changed = true;
- }
- erase(CallGetBlkInvoke);
- return changed;
- }
-
- void
- lowerBlockBuiltin(CallInst *CI, Function *InvF, Value *Ctx, Value *CtxLen,
- Value *CtxAlign, const std::string& DemangledName) {
- mutateCallInstSPIRV (M, CI, [=](CallInst *CI, std::vector<Value *> &Args) {
- size_t I = 0;
- size_t E = Args.size();
- for (; I != E; ++I) {
- if (isPointerToOpaqueStructType(Args[I]->getType(),
- SPIR_TYPE_NAME_BLOCK_T)) {
- break;
- }
- }
- assert (I < E);
- Args[I] = castToVoidFuncPtr(InvF);
- if (I + 1 == E) {
- Args.push_back(Ctx);
- Args.push_back(CtxLen);
- Args.push_back(CtxAlign);
- } else {
- Args.insert(Args.begin() + I + 1, CtxAlign);
- Args.insert(Args.begin() + I + 1, CtxLen);
- Args.insert(Args.begin() + I + 1, Ctx);
- }
- if (DemangledName == kOCLBuiltinName::EnqueueKernel) {
- // Insert event arguments if there are not.
- if (!isa<IntegerType>(Args[3]->getType())) {
- Args.insert(Args.begin() + 3, getInt32(M, 0));
- Args.insert(Args.begin() + 4, getOCLNullClkEventPtr());
- }
- if (!isOCLClkEventPtrType(Args[5]->getType()))
- Args.insert(Args.begin() + 5, getOCLNullClkEventPtr());
- }
- return getSPIRVFuncName(OCLSPIRVBuiltinMap::map(DemangledName));
- });
- }
- /// Transform return of a block.
- /// The function returning a block is inlined since the context cannot be
- /// passed to another function.
- /// Returns true of module is changed.
- bool
- lowerReturnBlock(ReturnInst *Ret, Value *CallBlkBind, bool &Inlined) {
- auto F = Ret->getParent()->getParent();
- auto changed = false;
- for (auto UI = F->user_begin(), UE = F->user_end(); UI != UE;) {
- auto U = *UI++;
- dumpUsers(U);
- auto Inst = dyn_cast<Instruction>(U);
- if (Inst && Inst->use_empty()) {
- erase(Inst);
- changed = true;
- continue;
- }
- auto CI = dyn_cast<CallInst>(U);
- if(!CI || CI->getCalledFunction() != F)
- continue;
-
- DEBUG(dbgs() << "[lowerReturnBlock] inline " << F->getName() << '\n');
- auto CG = &getAnalysis<CallGraphWrapperPass>().getCallGraph();
- auto ACT = &getAnalysis<AssumptionCacheTracker>();
- std::function<AssumptionCache &(Function &)> GetAssumptionCache = [&](
- Function &F) -> AssumptionCache & { return ACT->getAssumptionCache(F); };
- InlineFunctionInfo IFI(CG, &GetAssumptionCache);
- InlineFunction(CI, IFI);
- Inlined = true;
- }
- return changed || Inlined;
- }
-
- /// Looking for a global variables initialized by opencl.block*. If found,
- /// check
- /// its users. If users are trivially dead, erase them. If the global variable
- /// has no users left after that, erase it too.
- void EraseUselessGlobalVars() {
- std::vector<GlobalVariable*> GlobalVarsToDelete;
- for(GlobalVariable &G : M->globals()) {
- if(!G.hasInitializer())
- continue;
- Type *T = G.getInitializer()->getType();
- if(!T->isPointerTy())
- continue;
- T = cast<PointerType>(T)->getElementType();
- if(!T->isStructTy())
- continue;
- StringRef STName = cast<StructType>(T)->getName();
- if(STName != "opencl.block")
- continue;
-
- std::vector<User*> UsersToDelete;
- for (User *U : G.users())
- if (U->use_empty())
- UsersToDelete.push_back(U);
- for (User* U : UsersToDelete)
- erase(dyn_cast<Instruction>(U));
-
- if(G.use_empty()) {
- GlobalVarsToDelete.push_back(&G);
- }
- }
- for(GlobalVariable *G: GlobalVarsToDelete) {
- if (G->hasInitializer()) {
- Constant *Init = G->getInitializer();
- G->setInitializer(nullptr);
- if (llvm::isSafeToDestroyConstant(Init))
- Init->destroyConstant();
- }
- M->getGlobalList().erase(G);
- }
- }
-
- /// This method identifies F as an enqueued function iff:
- /// 1. F is bitcasted to a pointer, and
- /// 2. is passed to a function call of _Z21__spirv_EnqueueKernel
- /// Returns true if F is enqueued function, false otherwise.
- bool isEnqueuedFunction(Function &F) const {
- for (User* U : F.users()) {
- if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U)) {
- if (CE->getOpcode() != Instruction::BitCast)
- continue;
- if (!CE->getType()->isPointerTy())
- continue;
- // lowerBlockBind() should already have substituted last argument
- // of enqueue_kernel() call with arguments of spir_block_bind().
- for (User *UU : CE->users())
- if (CallInst* C = dyn_cast<CallInst>(UU))
- if (Function *CF = C->getCalledFunction())
- if (CF->getName().startswith("_Z21__spirv_EnqueueKernel"))
- return true;
- }
- }
- return false;
- }
-
- /// Looking for functions which first argument is i8* %.block_descriptor
- /// If users of this argument are dead, erase them.
- /// After that clone the found function, removing its first argument
- /// Then adjust all users/callers of the function with new arguments
- /// Implementation of this function is based on
- /// the dead argument elimination pass.
- void EliminateDeadArgs() {
- std::vector<Function*> FunctionsToDelete;
- for (Function &F : M->functions()) {
- if(F.arg_size() < 1)
- continue;
- auto FirstArg = F.arg_begin();
- if (FirstArg->getName() != ".block_descriptor")
- continue;
-
- // Skip the function if it is an enqueued kernel, because per SPIR-V spec,
- // function invoked with OpEnqueueKernel must have at least one argument
- // of type i8*
- if (isEnqueuedFunction(F))
- continue;
-
- std::vector<User*> UsersToDelete;
- for (User *U : FirstArg->users())
- if (U->use_empty())
- UsersToDelete.push_back(U);
-
- for (User *U : UsersToDelete)
- erase(dyn_cast<Instruction>(U));
- UsersToDelete.clear();
-
- if (!FirstArg->use_empty())
- continue;
-
- // Create new function without block descriptor argument.
- ValueToValueMapTy VMap;
- // If any of the arguments to the function are in the VMap,
- // the arguments are deleted from the resultant function.
- VMap[&*FirstArg] = llvm::UndefValue::get(FirstArg->getType());
- Function *NF = CloneFunction(&F, VMap);
- NF->takeName(&F);
-
- // Redirect all users of the old function to the new one.
- for (User *U : F.users()) {
- ConstantExpr *CE = dyn_cast<ConstantExpr>(U);
- CallSite CS(U);
- if (CE && CE->getOpcode() == Instruction::BitCast) {
- Constant *NewCE = ConstantExpr::getBitCast(NF, CE->getType());
- U->replaceAllUsesWith(NewCE);
- } else if (CS) {
- assert(isa<CallInst>(CS.getInstruction()) && "Call instruction is expected");
- CallInst * Call = cast<CallInst>(CS.getInstruction());
-
- std::vector<Value*> Args;
- auto I = CS.arg_begin();
- Args.assign(++I, CS.arg_end()); // Skip first argument.
- CallInst *New = CallInst::Create(NF, Args, "", Call);
- assert(New->getType() == Call->getType());
- New->setCallingConv(CS.getCallingConv());
- New->setAttributes(NF->getAttributes());
- if (Call->isTailCall())
- New->setTailCall();
- New->setDebugLoc(Call->getDebugLoc());
- New->takeName(Call);
- Call->replaceAllUsesWith(New);
- UsersToDelete.push_back(Call);
- } else {
- llvm_unreachable("Unexpected user of function");
- }
- }
- for(User* U : UsersToDelete)
- erase(cast<Instruction>(U));
- UsersToDelete.clear();
- FunctionsToDelete.push_back(&F);
- } // iteration over module's functions.
-
- for (Function *F : FunctionsToDelete)
- erase(F);
- }
-
- void
- getBlockInvokeFuncAndContext(Value *Blk, Function **PInvF, Value **PCtx,
- Value **PCtxLen = nullptr, Value **PCtxAlign = nullptr){
- Function *InvF = nullptr;
- Value *Ctx = nullptr;
- Value *CtxLen = nullptr;
- Value *CtxAlign = nullptr;
- if (auto CallBlkBind = dyn_cast<CallInst>(Blk)) {
- assert(CallBlkBind->getCalledFunction()->getName() ==
- SPIR_INTRINSIC_BLOCK_BIND && "Invalid block");
- InvF = dyn_cast<Function>(
- CallBlkBind->getArgOperand(0)->stripPointerCasts());
- CtxLen = CallBlkBind->getArgOperand(1);
- CtxAlign = CallBlkBind->getArgOperand(2);
- Ctx = CallBlkBind->getArgOperand(3);
- } else if (auto F = dyn_cast<Function>(Blk->stripPointerCasts())) {
- InvF = F;
- Ctx = Constant::getNullValue(IntegerType::getInt8PtrTy(M->getContext()));
- } else if (auto Load = dyn_cast<LoadInst>(Blk)) {
- auto Op = Load->getPointerOperand();
- if (auto GV = dyn_cast<GlobalVariable>(Op)) {
- if (GV->isConstant()) {
- InvF = cast<Function>(GV->getInitializer()->stripPointerCasts());
- Ctx = Constant::getNullValue(IntegerType::getInt8PtrTy(M->getContext()));
- } else {
- llvm_unreachable("load non-constant block?");
- }
- } else {
- llvm_unreachable("Loading block from non global?");
- }
- } else {
- llvm_unreachable("Invalid block");
- }
- DEBUG(dbgs() << " Block invocation func: " << InvF->getName() << '\n' <<
- " Block context: " << *Ctx << '\n');
- assert(InvF && Ctx && "Invalid block");
- if (PInvF)
- *PInvF = InvF;
- if (PCtx)
- *PCtx = Ctx;
- if (PCtxLen)
- *PCtxLen = CtxLen;
- if (PCtxAlign)
- *PCtxAlign = CtxAlign;
- }
- void
- erase(Instruction *I) {
- if (!I)
- return;
- if (I->use_empty()) {
- I->dropAllReferences();
- I->eraseFromParent();
- }
- else
- dumpUsers(I);
- }
- void
- erase(ConstantExpr *I) {
- if (!I)
- return;
- if (I->use_empty()) {
- I->dropAllReferences();
- I->destroyConstant();
- } else
- dumpUsers(I);
- }
- void
- erase(Function *F) {
- if (!F)
- return;
- if (!F->use_empty()) {
- dumpUsers(F);
- return;
- }
-
- F->dropAllReferences();
-
- auto &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
- CallGraphNode* CGN = CG[F];
-
- if (CGN->getNumReferences() != 0) {
- return;
- }
-
- CGN->removeAllCalledFunctions();
- delete CG.removeFunctionFromModule(CGN);
- }
-
- llvm::PointerType* getOCLClkEventType() {
- return getOrCreateOpaquePtrType(M, SPIR_TYPE_NAME_CLK_EVENT_T,
- SPIRAS_Global);
- }
-
- llvm::PointerType* getOCLClkEventPtrType() {
- return PointerType::get(getOCLClkEventType(), SPIRAS_Generic);
- }
-
- bool isOCLClkEventPtrType(Type *T) {
- if (auto PT = dyn_cast<PointerType>(T))
- return isPointerToOpaqueStructType(
- PT->getElementType(), SPIR_TYPE_NAME_CLK_EVENT_T);
- return false;
- }
-
- llvm::Constant* getOCLNullClkEventPtr() {
- return Constant::getNullValue(getOCLClkEventPtrType());
- }
-
- void dumpGetBlockInvokeUsers(StringRef Prompt) {
- DEBUG(dbgs() << Prompt);
- dumpUsers(M->getFunction(SPIR_INTRINSIC_GET_BLOCK_INVOKE));
- }
-};
-
-char SPIRVLowerOCLBlocks::ID = 0;
-}
-
-INITIALIZE_PASS_BEGIN(SPIRVLowerOCLBlocks, "spvblocks",
- "SPIR-V lower OCL blocks", false, false)
-INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
-INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
-INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
-INITIALIZE_PASS_END(SPIRVLowerOCLBlocks, "spvblocks",
- "SPIR-V lower OCL blocks", false, false)
-
-ModulePass *llvm::createSPIRVLowerOCLBlocks() {
- return new SPIRVLowerOCLBlocks();
-}
-
-#endif /* OCLLOWERBLOCKS_H_ */
+//===- SPIRVLowerOCLBlocks.cpp - Lower OpenCL blocks ------------*- C++ -*-===// +// +// The LLVM/SPIR-V 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file implements lowering of OpenCL blocks to functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef OCLLOWERBLOCKS_H_ +#define OCLLOWERBLOCKS_H_ + +#include "SPIRVInternal.h" +#include "OCLUtil.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/CallGraph.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Operator.h" +#include "llvm/Pass.h" +#include "llvm/PassSupport.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/GlobalStatus.h" +#include <iostream> +#include <list> +#include <memory> +#include <set> +#include <sstream> +#include <vector> + +#define DEBUG_TYPE "spvblocks" + +using namespace llvm; +using namespace SPIRV; +using namespace OCLUtil; + +namespace SPIRV{ + +/// Lower SPIR2 blocks to function calls. +/// +/// SPIR2 representation of blocks: +/// +/// block = spir_block_bind(bitcast(block_func), context_len, context_align, +/// context) +/// block_func_ptr = bitcast(spir_get_block_invoke(block)) +/// context_ptr = spir_get_block_context(block) +/// ret = block_func_ptr(context_ptr, args) +/// +/// Propagates block_func to each spir_get_block_invoke through def-use chain of +/// spir_block_bind, so that +/// ret = block_func(context, args) +class SPIRVLowerOCLBlocks: public ModulePass { +public: + SPIRVLowerOCLBlocks():ModulePass(ID), M(nullptr){ + initializeSPIRVLowerOCLBlocksPass(*PassRegistry::getPassRegistry()); + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<CallGraphWrapperPass>(); + AU.addRequired<AAResultsWrapperPass>(); + AU.addRequired<AssumptionCacheTracker>(); + } + + virtual bool runOnModule(Module &Module) { + M = &Module; + lowerBlockBind(); + lowerGetBlockInvoke(); + lowerGetBlockContext(); + EraseUselessGlobalVars(); + EliminateDeadArgs(); + erase(M->getFunction(SPIR_INTRINSIC_GET_BLOCK_INVOKE)); + erase(M->getFunction(SPIR_INTRINSIC_GET_BLOCK_CONTEXT)); + erase(M->getFunction(SPIR_INTRINSIC_BLOCK_BIND)); + DEBUG(dbgs() << "------- After OCLLowerBlocks ------------\n" << + *M << '\n'); + return true; + } + + static char ID; +private: + const static int MaxIter = 1000; + Module *M; + + bool + lowerBlockBind() { + auto F = M->getFunction(SPIR_INTRINSIC_BLOCK_BIND); + if (!F) + return false; + int Iter = MaxIter; + while(lowerBlockBind(F) && Iter > 0){ + Iter--; + DEBUG(dbgs() << "-------------- after iteration " << MaxIter - Iter << + " --------------\n" << *M << '\n'); + } + assert(Iter > 0 && "Too many iterations"); + return true; + } + + bool + eraseUselessFunctions() { + bool changed = false; + for (auto I = M->begin(), E = M->end(); I != E;) { + Function *F = &(*I++); + if (!GlobalValue::isInternalLinkage(F->getLinkage()) && + !F->isDeclaration()) + continue; + + dumpUsers(F, "[eraseUselessFunctions] "); + for (auto UI = F->user_begin(), UE = F->user_end(); UI != UE;) { + auto U = *UI++; + if (auto CE = dyn_cast<ConstantExpr>(U)){ + if (CE->use_empty()) { + CE->dropAllReferences(); + changed = true; + } + } + } + + if (!F->use_empty()) { + continue; + } + + auto &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph(); + CallGraphNode* CGN = CG[F]; + + if (CGN->getNumReferences() != 0) { + continue; + } + + erase(F); + changed = true; + } + return changed; + } + + void + lowerGetBlockInvoke() { + if (auto F = M->getFunction(SPIR_INTRINSIC_GET_BLOCK_INVOKE)) { + for (auto UI = F->user_begin(), UE = F->user_end(); UI != UE;) { + auto CI = dyn_cast<CallInst>(*UI++); + assert(CI && "Invalid usage of spir_get_block_invoke"); + lowerGetBlockInvoke(CI); + } + } + } + + void + lowerGetBlockContext() { + if (auto F = M->getFunction(SPIR_INTRINSIC_GET_BLOCK_CONTEXT)) { + for (auto UI = F->user_begin(), UE = F->user_end(); UI != UE;) { + auto CI = dyn_cast<CallInst>(*UI++); + assert(CI && "Invalid usage of spir_get_block_context"); + lowerGetBlockContext(CI); + } + } + } + /// Lower calls of spir_block_bind. + /// Return true if the Module is changed. + bool + lowerBlockBind(Function *BlockBindFunc) { + bool changed = false; + for (auto I = BlockBindFunc->user_begin(), E = BlockBindFunc->user_end(); + I != E;) { + DEBUG(dbgs() << "[lowerBlockBind] " << **I << '\n'); + // Handle spir_block_bind(bitcast(block_func), context_len, + // context_align, context) + auto CallBlkBind = cast<CallInst>(*I++); + Function *InvF = nullptr; + Value *Ctx = nullptr; + Value *CtxLen = nullptr; + Value *CtxAlign = nullptr; + getBlockInvokeFuncAndContext(CallBlkBind, &InvF, &Ctx, &CtxLen, + &CtxAlign); + for (auto II = CallBlkBind->user_begin(), EE = CallBlkBind->user_end(); + II != EE;) { + auto BlkUser = *II++; + SPIRVDBG(dbgs() << " Block user: " << *BlkUser << '\n'); + if (auto Ret = dyn_cast<ReturnInst>(BlkUser)) { + bool Inlined = false; + changed |= lowerReturnBlock(Ret, CallBlkBind, Inlined); + if (Inlined) + return true; + } else if (auto CI = dyn_cast<CallInst>(BlkUser)){ + auto CallBindF = CI->getCalledFunction(); + auto Name = CallBindF->getName(); + std::string DemangledName; + if (Name == SPIR_INTRINSIC_GET_BLOCK_INVOKE) { + assert(CI->getArgOperand(0) == CallBlkBind); + changed |= lowerGetBlockInvoke(CI, cast<Function>(InvF)); + } else if (Name == SPIR_INTRINSIC_GET_BLOCK_CONTEXT) { + assert(CI->getArgOperand(0) == CallBlkBind); + // Handle context_ptr = spir_get_block_context(block) + lowerGetBlockContext(CI, Ctx); + changed = true; + } else if (oclIsBuiltin(Name, &DemangledName)) { + lowerBlockBuiltin(CI, InvF, Ctx, CtxLen, CtxAlign, DemangledName); + changed = true; + } else + llvm_unreachable("Invalid block user"); + } + } + erase(CallBlkBind); + } + changed |= eraseUselessFunctions(); + return changed; + } + + void + lowerGetBlockContext(CallInst *CallGetBlkCtx, Value *Ctx = nullptr) { + if (!Ctx) + getBlockInvokeFuncAndContext(CallGetBlkCtx->getArgOperand(0), nullptr, + &Ctx); + CallGetBlkCtx->replaceAllUsesWith(Ctx); + DEBUG(dbgs() << " [lowerGetBlockContext] " << *CallGetBlkCtx << " => " << + *Ctx << "\n\n"); + erase(CallGetBlkCtx); + } + + bool + lowerGetBlockInvoke(CallInst *CallGetBlkInvoke, + Function *InvokeF = nullptr) { + bool changed = false; + for (auto UI = CallGetBlkInvoke->user_begin(), + UE = CallGetBlkInvoke->user_end(); + UI != UE;) { + // Handle block_func_ptr = bitcast(spir_get_block_invoke(block)) + auto CallInv = cast<Instruction>(*UI++); + auto Cast = dyn_cast<BitCastInst>(CallInv); + if (Cast) + CallInv = dyn_cast<Instruction>(*CallInv->user_begin()); + DEBUG(dbgs() << "[lowerGetBlockInvoke] " << *CallInv); + // Handle ret = block_func_ptr(context_ptr, args) + auto CI = cast<CallInst>(CallInv); + auto F = CI->getCalledValue(); + if (InvokeF == nullptr) { + getBlockInvokeFuncAndContext(CallGetBlkInvoke->getArgOperand(0), + &InvokeF, nullptr); + assert(InvokeF); + } + assert(F->getType() == InvokeF->getType()); + CI->replaceUsesOfWith(F, InvokeF); + DEBUG(dbgs() << " => " << *CI << "\n\n"); + erase(Cast); + changed = true; + } + erase(CallGetBlkInvoke); + return changed; + } + + void + lowerBlockBuiltin(CallInst *CI, Function *InvF, Value *Ctx, Value *CtxLen, + Value *CtxAlign, const std::string& DemangledName) { + mutateCallInstSPIRV (M, CI, [=](CallInst *CI, std::vector<Value *> &Args) { + size_t I = 0; + size_t E = Args.size(); + for (; I != E; ++I) { + if (isPointerToOpaqueStructType(Args[I]->getType(), + SPIR_TYPE_NAME_BLOCK_T)) { + break; + } + } + assert (I < E); + Args[I] = castToVoidFuncPtr(InvF); + if (I + 1 == E) { + Args.push_back(Ctx); + Args.push_back(CtxLen); + Args.push_back(CtxAlign); + } else { + Args.insert(Args.begin() + I + 1, CtxAlign); + Args.insert(Args.begin() + I + 1, CtxLen); + Args.insert(Args.begin() + I + 1, Ctx); + } + if (DemangledName == kOCLBuiltinName::EnqueueKernel) { + // Insert event arguments if there are not. + if (!isa<IntegerType>(Args[3]->getType())) { + Args.insert(Args.begin() + 3, getInt32(M, 0)); + Args.insert(Args.begin() + 4, getOCLNullClkEventPtr()); + } + if (!isOCLClkEventPtrType(Args[5]->getType())) + Args.insert(Args.begin() + 5, getOCLNullClkEventPtr()); + } + return getSPIRVFuncName(OCLSPIRVBuiltinMap::map(DemangledName)); + }); + } + /// Transform return of a block. + /// The function returning a block is inlined since the context cannot be + /// passed to another function. + /// Returns true of module is changed. + bool + lowerReturnBlock(ReturnInst *Ret, Value *CallBlkBind, bool &Inlined) { + auto F = Ret->getParent()->getParent(); + auto changed = false; + for (auto UI = F->user_begin(), UE = F->user_end(); UI != UE;) { + auto U = *UI++; + dumpUsers(U); + auto Inst = dyn_cast<Instruction>(U); + if (Inst && Inst->use_empty()) { + erase(Inst); + changed = true; + continue; + } + auto CI = dyn_cast<CallInst>(U); + if(!CI || CI->getCalledFunction() != F) + continue; + + DEBUG(dbgs() << "[lowerReturnBlock] inline " << F->getName() << '\n'); + auto CG = &getAnalysis<CallGraphWrapperPass>().getCallGraph(); + auto ACT = &getAnalysis<AssumptionCacheTracker>(); + std::function<AssumptionCache &(Function &)> GetAssumptionCache = [&]( + Function &F) -> AssumptionCache & { return ACT->getAssumptionCache(F); }; + InlineFunctionInfo IFI(CG, &GetAssumptionCache); + InlineFunction(CI, IFI); + Inlined = true; + } + return changed || Inlined; + } + + /// Looking for a global variables initialized by opencl.block*. If found, + /// check + /// its users. If users are trivially dead, erase them. If the global variable + /// has no users left after that, erase it too. + void EraseUselessGlobalVars() { + std::vector<GlobalVariable*> GlobalVarsToDelete; + for(GlobalVariable &G : M->globals()) { + if(!G.hasInitializer()) + continue; + Type *T = G.getInitializer()->getType(); + if(!T->isPointerTy()) + continue; + T = cast<PointerType>(T)->getElementType(); + if(!T->isStructTy()) + continue; + StringRef STName = cast<StructType>(T)->getName(); + if(STName != "opencl.block") + continue; + + std::vector<User*> UsersToDelete; + for (User *U : G.users()) + if (U->use_empty()) + UsersToDelete.push_back(U); + for (User* U : UsersToDelete) + erase(dyn_cast<Instruction>(U)); + + if(G.use_empty()) { + GlobalVarsToDelete.push_back(&G); + } + } + for(GlobalVariable *G: GlobalVarsToDelete) { + if (G->hasInitializer()) { + Constant *Init = G->getInitializer(); + G->setInitializer(nullptr); + if (llvm::isSafeToDestroyConstant(Init)) + Init->destroyConstant(); + } + M->getGlobalList().erase(G); + } + } + + /// This method identifies F as an enqueued function iff: + /// 1. F is bitcasted to a pointer, and + /// 2. is passed to a function call of _Z21__spirv_EnqueueKernel + /// Returns true if F is enqueued function, false otherwise. + bool isEnqueuedFunction(Function &F) const { + for (User* U : F.users()) { + if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U)) { + if (CE->getOpcode() != Instruction::BitCast) + continue; + if (!CE->getType()->isPointerTy()) + continue; + // lowerBlockBind() should already have substituted last argument + // of enqueue_kernel() call with arguments of spir_block_bind(). + for (User *UU : CE->users()) + if (CallInst* C = dyn_cast<CallInst>(UU)) + if (Function *CF = C->getCalledFunction()) + if (CF->getName().startswith("_Z21__spirv_EnqueueKernel")) + return true; + } + } + return false; + } + + /// Looking for functions which first argument is i8* %.block_descriptor + /// If users of this argument are dead, erase them. + /// After that clone the found function, removing its first argument + /// Then adjust all users/callers of the function with new arguments + /// Implementation of this function is based on + /// the dead argument elimination pass. + void EliminateDeadArgs() { + std::vector<Function*> FunctionsToDelete; + for (Function &F : M->functions()) { + if(F.arg_size() < 1) + continue; + auto FirstArg = F.arg_begin(); + if (FirstArg->getName() != ".block_descriptor") + continue; + + // Skip the function if it is an enqueued kernel, because per SPIR-V spec, + // function invoked with OpEnqueueKernel must have at least one argument + // of type i8* + if (isEnqueuedFunction(F)) + continue; + + std::vector<User*> UsersToDelete; + for (User *U : FirstArg->users()) + if (U->use_empty()) + UsersToDelete.push_back(U); + + for (User *U : UsersToDelete) + erase(dyn_cast<Instruction>(U)); + UsersToDelete.clear(); + + if (!FirstArg->use_empty()) + continue; + + // Create new function without block descriptor argument. + ValueToValueMapTy VMap; + // If any of the arguments to the function are in the VMap, + // the arguments are deleted from the resultant function. + VMap[&*FirstArg] = llvm::UndefValue::get(FirstArg->getType()); + Function *NF = CloneFunction(&F, VMap); + NF->takeName(&F); + + // Redirect all users of the old function to the new one. + for (User *U : F.users()) { + ConstantExpr *CE = dyn_cast<ConstantExpr>(U); + CallSite CS(U); + if (CE && CE->getOpcode() == Instruction::BitCast) { + Constant *NewCE = ConstantExpr::getBitCast(NF, CE->getType()); + U->replaceAllUsesWith(NewCE); + } else if (CS) { + assert(isa<CallInst>(CS.getInstruction()) && "Call instruction is expected"); + CallInst * Call = cast<CallInst>(CS.getInstruction()); + + std::vector<Value*> Args; + auto I = CS.arg_begin(); + Args.assign(++I, CS.arg_end()); // Skip first argument. + CallInst *New = CallInst::Create(NF, Args, "", Call); + assert(New->getType() == Call->getType()); + New->setCallingConv(CS.getCallingConv()); + New->setAttributes(NF->getAttributes()); + if (Call->isTailCall()) + New->setTailCall(); + New->setDebugLoc(Call->getDebugLoc()); + New->takeName(Call); + Call->replaceAllUsesWith(New); + UsersToDelete.push_back(Call); + } else { + llvm_unreachable("Unexpected user of function"); + } + } + for(User* U : UsersToDelete) + erase(cast<Instruction>(U)); + UsersToDelete.clear(); + FunctionsToDelete.push_back(&F); + } // iteration over module's functions. + + for (Function *F : FunctionsToDelete) + erase(F); + } + + void + getBlockInvokeFuncAndContext(Value *Blk, Function **PInvF, Value **PCtx, + Value **PCtxLen = nullptr, Value **PCtxAlign = nullptr){ + Function *InvF = nullptr; + Value *Ctx = nullptr; + Value *CtxLen = nullptr; + Value *CtxAlign = nullptr; + if (auto CallBlkBind = dyn_cast<CallInst>(Blk)) { + assert(CallBlkBind->getCalledFunction()->getName() == + SPIR_INTRINSIC_BLOCK_BIND && "Invalid block"); + InvF = dyn_cast<Function>( + CallBlkBind->getArgOperand(0)->stripPointerCasts()); + CtxLen = CallBlkBind->getArgOperand(1); + CtxAlign = CallBlkBind->getArgOperand(2); + Ctx = CallBlkBind->getArgOperand(3); + } else if (auto F = dyn_cast<Function>(Blk->stripPointerCasts())) { + InvF = F; + Ctx = Constant::getNullValue(IntegerType::getInt8PtrTy(M->getContext())); + } else if (auto Load = dyn_cast<LoadInst>(Blk)) { + auto Op = Load->getPointerOperand(); + if (auto GV = dyn_cast<GlobalVariable>(Op)) { + if (GV->isConstant()) { + InvF = cast<Function>(GV->getInitializer()->stripPointerCasts()); + Ctx = Constant::getNullValue(IntegerType::getInt8PtrTy(M->getContext())); + } else { + llvm_unreachable("load non-constant block?"); + } + } else { + llvm_unreachable("Loading block from non global?"); + } + } else { + llvm_unreachable("Invalid block"); + } + DEBUG(dbgs() << " Block invocation func: " << InvF->getName() << '\n' << + " Block context: " << *Ctx << '\n'); + assert(InvF && Ctx && "Invalid block"); + if (PInvF) + *PInvF = InvF; + if (PCtx) + *PCtx = Ctx; + if (PCtxLen) + *PCtxLen = CtxLen; + if (PCtxAlign) + *PCtxAlign = CtxAlign; + } + void + erase(Instruction *I) { + if (!I) + return; + if (I->use_empty()) { + I->dropAllReferences(); + I->eraseFromParent(); + } + else + dumpUsers(I); + } + void + erase(ConstantExpr *I) { + if (!I) + return; + if (I->use_empty()) { + I->dropAllReferences(); + I->destroyConstant(); + } else + dumpUsers(I); + } + void + erase(Function *F) { + if (!F) + return; + if (!F->use_empty()) { + dumpUsers(F); + return; + } + + F->dropAllReferences(); + + auto &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph(); + CallGraphNode* CGN = CG[F]; + + if (CGN->getNumReferences() != 0) { + return; + } + + CGN->removeAllCalledFunctions(); + delete CG.removeFunctionFromModule(CGN); + } + + llvm::PointerType* getOCLClkEventType() { + return getOrCreateOpaquePtrType(M, SPIR_TYPE_NAME_CLK_EVENT_T, + SPIRAS_Global); + } + + llvm::PointerType* getOCLClkEventPtrType() { + return PointerType::get(getOCLClkEventType(), SPIRAS_Generic); + } + + bool isOCLClkEventPtrType(Type *T) { + if (auto PT = dyn_cast<PointerType>(T)) + return isPointerToOpaqueStructType( + PT->getElementType(), SPIR_TYPE_NAME_CLK_EVENT_T); + return false; + } + + llvm::Constant* getOCLNullClkEventPtr() { + return Constant::getNullValue(getOCLClkEventPtrType()); + } + + void dumpGetBlockInvokeUsers(StringRef Prompt) { + DEBUG(dbgs() << Prompt); + dumpUsers(M->getFunction(SPIR_INTRINSIC_GET_BLOCK_INVOKE)); + } +}; + +char SPIRVLowerOCLBlocks::ID = 0; +} + +INITIALIZE_PASS_BEGIN(SPIRVLowerOCLBlocks, "spvblocks", + "SPIR-V lower OCL blocks", false, false) +INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass) +INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) +INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) +INITIALIZE_PASS_END(SPIRVLowerOCLBlocks, "spvblocks", + "SPIR-V lower OCL blocks", false, false) + +ModulePass *llvm::createSPIRVLowerOCLBlocks() { + return new SPIRVLowerOCLBlocks(); +} + +#endif /* OCLLOWERBLOCKS_H_ */ diff --git a/lib/SPIRV/SPIRVReader.cpp b/lib/SPIRV/SPIRVReader.cpp index 2391b83..42bdb97 100644 --- a/lib/SPIRV/SPIRVReader.cpp +++ b/lib/SPIRV/SPIRVReader.cpp @@ -1,3119 +1,3119 @@ -//===- SPIRVReader.cpp - Converts SPIR-V to LLVM ----------------*- C++ -*-===//
-//
-// The LLVM/SPIR-V 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file implements conversion of SPIR-V binary to LLVM IR.
-///
-//===----------------------------------------------------------------------===//
-#include "SPIRVUtil.h"
-#include "SPIRVType.h"
-#include "SPIRVValue.h"
-#include "SPIRVModule.h"
-#include "SPIRVFunction.h"
-#include "SPIRVBasicBlock.h"
-#include "SPIRVInstruction.h"
-#include "SPIRVExtInst.h"
-#include "SPIRVInternal.h"
-#include "SPIRVMDBuilder.h"
-#include "OCLUtil.h"
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DIBuilder.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/IR/LegacyPassManager.h"
-#include "llvm/IR/Metadata.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Operator.h"
-#include "llvm/IR/Type.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/BinaryFormat/Dwarf.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <algorithm>
-#include <cstdlib>
-#include <functional>
-#include <fstream>
-#include <iostream>
-#include <iterator>
-#include <map>
-#include <set>
-#include <sstream>
-#include <string>
-
-#define DEBUG_TYPE "spirv"
-
-using namespace std;
-using namespace llvm;
-using namespace SPIRV;
-using namespace OCLUtil;
-
-namespace SPIRV{
-
-cl::opt<bool> SPIRVEnableStepExpansion("spirv-expand-step", cl::init(true),
- cl::desc("Enable expansion of OpenCL step and smoothstep function"));
-
-cl::opt<bool> SPIRVGenKernelArgNameMD("spirv-gen-kernel-arg-name-md",
- cl::init(false), cl::desc("Enable generating OpenCL kernel argument name "
- "metadata"));
-
-cl::opt<bool> SPIRVGenImgTypeAccQualPostfix("spirv-gen-image-type-acc-postfix",
- cl::init(false), cl::desc("Enable generating access qualifier postfix"
- " in OpenCL image type names"));
-
-// Prefix for placeholder global variable name.
-const char* kPlaceholderPrefix = "placeholder.";
-
-// Save the translated LLVM before validation for debugging purpose.
-static bool DbgSaveTmpLLVM = false;
-static const char *DbgTmpLLVMFileName = "_tmp_llvmbil.ll";
-
-namespace kOCLTypeQualifierName {
- const static char *Const = "const";
- const static char *Volatile = "volatile";
- const static char *Restrict = "restrict";
- const static char *Pipe = "pipe";
-}
-
-typedef std::pair < unsigned, AttributeList > AttributeWithIndex;
-
-static bool
-isOpenCLKernel(SPIRVFunction *BF) {
- return BF->getModule()->isEntryPoint(ExecutionModelKernel, BF->getId());
-}
-
-static void
-dumpLLVM(Module *M, const std::string &FName) {
- std::error_code EC;
- raw_fd_ostream FS(FName, EC, sys::fs::F_None);
- if (EC) {
- FS << *M;
- FS.close();
- }
-}
-
-static MDNode*
-getMDNodeStringIntVec(LLVMContext *Context,
- const std::vector<SPIRVWord>& IntVals) {
- std::vector<Metadata*> ValueVec;
- for (auto &I:IntVals)
- ValueVec.push_back(ConstantAsMetadata::get(
- ConstantInt::get(Type::getInt32Ty(*Context), I)));
- return MDNode::get(*Context, ValueVec);
-}
-
-static MDNode*
-getMDTwoInt(LLVMContext *Context, unsigned Int1, unsigned Int2) {
- std::vector<Metadata*> ValueVec;
- ValueVec.push_back(ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(*Context), Int1)));
- ValueVec.push_back(ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(*Context), Int2)));
- return MDNode::get(*Context, ValueVec);
-}
-
-static void
-addOCLVersionMetadata(LLVMContext *Context, Module *M,
- const std::string &MDName, unsigned Major, unsigned Minor) {
- NamedMDNode *NamedMD = M->getOrInsertNamedMetadata(MDName);
- NamedMD->addOperand(getMDTwoInt(Context, Major, Minor));
-}
-
-static void
-addNamedMetadataStringSet(LLVMContext *Context, Module *M,
- const std::string &MDName, const std::set<std::string> &StrSet) {
- NamedMDNode *NamedMD = M->getOrInsertNamedMetadata(MDName);
- std::vector<Metadata*> ValueVec;
- for (auto &&Str : StrSet) {
- ValueVec.push_back(MDString::get(*Context, Str));
- }
- NamedMD->addOperand(MDNode::get(*Context, ValueVec));
-}
-
-static void
-addOCLKernelArgumentMetadata(LLVMContext *Context, const std::string &MDName,
- SPIRVFunction *BF, llvm::Function *Fn,
- std::function<Metadata *(SPIRVFunctionParameter *)>Func) {
- std::vector<Metadata*> ValueVec;
- BF->foreachArgument([&](SPIRVFunctionParameter *Arg) {
- ValueVec.push_back(Func(Arg));
- });
- Fn->setMetadata(MDName, MDNode::get(*Context, ValueVec));
-}
-
-class SPIRVToLLVMDbgTran {
-public:
- SPIRVToLLVMDbgTran(SPIRVModule *TBM, Module *TM)
- :BM(TBM), M(TM), SpDbg(BM), Builder(*M){
- Enable = BM->hasDebugInfo();
- }
-
- void createCompileUnit() {
- if (!Enable)
- return;
- auto File = SpDbg.getEntryPointFileStr(ExecutionModelKernel, 0);
- std::string BaseName;
- std::string Path;
- splitFileName(File, BaseName, Path);
- Builder.createCompileUnit(dwarf::DW_LANG_C99,
- Builder.createFile(BaseName, Path), "spirv", false, "", 0, "", DICompileUnit::LineTablesOnly);
- }
-
- void addDbgInfoVersion() {
- if (!Enable)
- return;
- M->addModuleFlag(Module::Warning, "Dwarf Version",
- dwarf::DWARF_VERSION);
- M->addModuleFlag(Module::Warning, "Debug Info Version",
- DEBUG_METADATA_VERSION);
- }
-
- DIFile* getDIFile(const std::string &FileName){
- return getOrInsert(FileMap, FileName, [=]() -> DIFile* {
- std::string BaseName;
- std::string Path;
- splitFileName(FileName, BaseName, Path);
- if (!BaseName.empty())
- return Builder.createFile(BaseName, Path);
- else
- return nullptr;
- });
- }
-
- DISubprogram* getDISubprogram(SPIRVFunction *SF, Function *F){
- return getOrInsert(FuncMap, F, [=](){
- auto DF = getDIFile(SpDbg.getFunctionFileStr(SF));
- auto FN = F->getName();
- auto LN = SpDbg.getFunctionLineNo(SF);
- return Builder.createFunction(DF, FN, FN, DF, LN,
- Builder.createSubroutineType(Builder.getOrCreateTypeArray(None)),
- Function::isInternalLinkage(F->getLinkage()),
- true, LN);
- });
- }
-
- void transDbgInfo(SPIRVValue *SV, Value *V) {
- if (!Enable || !SV->hasLine())
- return;
- if (auto I = dyn_cast<Instruction>(V)) {
- assert(SV->isInst() && "Invalid instruction");
- auto SI = static_cast<SPIRVInstruction *>(SV);
- assert(SI->getParent() &&
- SI->getParent()->getParent() &&
- "Invalid instruction");
- auto Line = SV->getLine();
- I->setDebugLoc(DebugLoc::get(Line->getLine(), Line->getColumn(),
- getDISubprogram(SI->getParent()->getParent(),
- I->getParent()->getParent())));
- }
- }
-
- void finalize() {
- if (!Enable)
- return;
- Builder.finalize();
- }
-
-private:
- SPIRVModule *BM;
- Module *M;
- SPIRVDbgInfo SpDbg;
- DIBuilder Builder;
- bool Enable;
- std::unordered_map<std::string, DIFile *> FileMap;
- std::unordered_map<Function *, DISubprogram *> FuncMap;
-
- void splitFileName(const std::string &FileName,
- std::string &BaseName,
- std::string &Path) {
- auto Loc = FileName.find_last_of("/\\");
- if (Loc != std::string::npos) {
- BaseName = FileName.substr(Loc + 1);
- Path = FileName.substr(0, Loc);
- } else {
- BaseName = FileName;
- Path = ".";
- }
- }
-};
-
-class SPIRVToLLVM {
-public:
- SPIRVToLLVM(Module *LLVMModule, SPIRVModule *TheSPIRVModule)
- :M(LLVMModule), BM(TheSPIRVModule), DbgTran(BM, M){
- assert(M);
- Context = &M->getContext();
- }
-
- std::string getOCLBuiltinName(SPIRVInstruction* BI);
- std::string getOCLConvertBuiltinName(SPIRVInstruction *BI);
- std::string getOCLGenericCastToPtrName(SPIRVInstruction *BI);
-
- Type *transType(SPIRVType *BT, bool IsClassMember = false);
- std::string transTypeToOCLTypeName(SPIRVType *BT, bool IsSigned = true);
- std::vector<Type *> transTypeVector(const std::vector<SPIRVType *>&);
- bool translate();
- bool transAddressingModel();
-
- Value *transValue(SPIRVValue *, Function *F, BasicBlock *,
- bool CreatePlaceHolder = true);
- Value *transValueWithoutDecoration(SPIRVValue *, Function *F, BasicBlock *,
- bool CreatePlaceHolder = true);
- Value *transDeviceEvent(SPIRVValue *BV, Function *F, BasicBlock *BB);
- Value *transEnqueuedBlock(SPIRVValue *BF, SPIRVValue *BC, SPIRVValue *BCSize,
- SPIRVValue *BCAligment, Function *F, BasicBlock *BB);
- bool transDecoration(SPIRVValue *, Value *);
- bool transAlign(SPIRVValue *, Value *);
- Instruction *transOCLBuiltinFromExtInst(SPIRVExtInst *BC, BasicBlock *BB);
- std::vector<Value *> transValue(const std::vector<SPIRVValue *>&, Function *F,
- BasicBlock *);
- Function *transFunction(SPIRVFunction *F);
- Instruction *transEnqueueKernelBI(SPIRVInstruction *BI, BasicBlock *BB);
- Instruction *transWGSizeBI(SPIRVInstruction *BI, BasicBlock *BB);
- bool transFPContractMetadata();
- bool transKernelMetadata();
- bool transNonTemporalMetadata(Instruction *I);
- bool transSourceLanguage();
- bool transSourceExtension();
- void transGeneratorMD();
- Value *transConvertInst(SPIRVValue* BV, Function* F, BasicBlock* BB);
- Instruction *transBuiltinFromInst(const std::string& FuncName,
- SPIRVInstruction* BI, BasicBlock* BB);
- Instruction *transOCLBuiltinFromInst(SPIRVInstruction *BI, BasicBlock *BB);
- Instruction *transSPIRVBuiltinFromInst(SPIRVInstruction *BI, BasicBlock *BB);
- Instruction *transOCLBarrierFence(SPIRVInstruction* BI, BasicBlock *BB);
- void transOCLVectorLoadStore(std::string& UnmangledName,
- std::vector<SPIRVWord> &BArgs);
-
- /// Post-process translated LLVM module for OpenCL.
- bool postProcessOCL();
-
- /// \brief Post-process OpenCL builtin functions returning struct type.
- ///
- /// Some OpenCL builtin functions are translated to SPIR-V instructions with
- /// struct type result, e.g. NDRange creation functions. Such functions
- /// need to be post-processed to return the struct through sret argument.
- bool postProcessOCLBuiltinReturnStruct(Function *F);
-
- /// \brief Post-process OpenCL builtin functions having array argument.
- ///
- /// These functions are translated to functions with array type argument
- /// first, then post-processed to have pointer arguments.
- bool postProcessOCLBuiltinWithArrayArguments(Function *F,
- const std::string &DemangledName);
-
- /// \brief Post-process OpImageSampleExplicitLod.
- /// sampled_image = __spirv_SampledImage__(image, sampler);
- /// return __spirv_ImageSampleExplicitLod__(sampled_image, image_operands,
- /// ...);
- /// =>
- /// read_image(image, sampler, ...)
- /// \return transformed call instruction.
- Instruction *postProcessOCLReadImage(SPIRVInstruction *BI, CallInst *CI,
- const std::string &DemangledName);
-
- /// \brief Post-process OpImageWrite.
- /// return write_image(image, coord, color, image_operands, ...);
- /// =>
- /// write_image(image, coord, ..., color)
- /// \return transformed call instruction.
- CallInst *postProcessOCLWriteImage(SPIRVInstruction *BI, CallInst *CI,
- const std::string &DemangledName);
-
- /// \brief Post-process OpBuildNDRange.
- /// OpBuildNDRange GlobalWorkSize, LocalWorkSize, GlobalWorkOffset
- /// =>
- /// call ndrange_XD(GlobalWorkOffset, GlobalWorkSize, LocalWorkSize)
- /// \return transformed call instruction.
- CallInst *postProcessOCLBuildNDRange(SPIRVInstruction *BI, CallInst *CI,
- const std::string &DemangledName);
-
- /// \brief Expand OCL builtin functions with scalar argument, e.g.
- /// step, smoothstep.
- /// gentype func (fp edge, gentype x)
- /// =>
- /// gentype func (gentype edge, gentype x)
- /// \return transformed call instruction.
- CallInst *expandOCLBuiltinWithScalarArg(CallInst* CI,
- const std::string &FuncName);
-
- /// \brief Post-process OpGroupAll and OpGroupAny instructions translation.
- /// i1 func (<n x i1> arg)
- /// =>
- /// i32 func (<n x i32> arg)
- /// \return transformed call instruction.
- Instruction *postProcessGroupAllAny(CallInst *CI,
- const std::string &DemangledName);
-
- typedef DenseMap<SPIRVType *, Type *> SPIRVToLLVMTypeMap;
- typedef DenseMap<SPIRVValue *, Value *> SPIRVToLLVMValueMap;
- typedef DenseMap<SPIRVValue *, Value *> SPIRVBlockToLLVMStructMap;
- typedef DenseMap<SPIRVFunction *, Function *> SPIRVToLLVMFunctionMap;
- typedef DenseMap<GlobalVariable *, SPIRVBuiltinVariableKind> BuiltinVarMap;
-
- // A SPIRV value may be translated to a load instruction of a placeholder
- // global variable. This map records load instruction of these placeholders
- // which are supposed to be replaced by the real values later.
- typedef std::map<SPIRVValue *, LoadInst*> SPIRVToLLVMPlaceholderMap;
-private:
- Module *M;
- BuiltinVarMap BuiltinGVMap;
- LLVMContext *Context;
- SPIRVModule *BM;
- SPIRVToLLVMTypeMap TypeMap;
- SPIRVToLLVMValueMap ValueMap;
- SPIRVToLLVMFunctionMap FuncMap;
- SPIRVBlockToLLVMStructMap BlockMap;
- SPIRVToLLVMPlaceholderMap PlaceholderMap;
- SPIRVToLLVMDbgTran DbgTran;
-
- Type *mapType(SPIRVType *BT, Type *T) {
- SPIRVDBG(dbgs() << *T << '\n';)
- TypeMap[BT] = T;
- return T;
- }
-
- // If a value is mapped twice, the existing mapped value is a placeholder,
- // which must be a load instruction of a global variable whose name starts
- // with kPlaceholderPrefix.
- Value *mapValue(SPIRVValue *BV, Value *V) {
- auto Loc = ValueMap.find(BV);
- if (Loc != ValueMap.end()) {
- if (Loc->second == V)
- return V;
- auto LD = dyn_cast<LoadInst>(Loc->second);
- auto Placeholder = dyn_cast<GlobalVariable>(LD->getPointerOperand());
- assert (LD && Placeholder &&
- Placeholder->getName().startswith(kPlaceholderPrefix) &&
- "A value is translated twice");
- // Replaces placeholders for PHI nodes
- LD->replaceAllUsesWith(V);
- LD->eraseFromParent();
- Placeholder->eraseFromParent();
- }
- ValueMap[BV] = V;
- return V;
- }
-
- bool isSPIRVBuiltinVariable(GlobalVariable *GV,
- SPIRVBuiltinVariableKind *Kind = nullptr) {
- auto Loc = BuiltinGVMap.find(GV);
- if (Loc == BuiltinGVMap.end())
- return false;
- if (Kind)
- *Kind = Loc->second;
- return true;
- }
- // OpenCL function always has NoUnwound attribute.
- // Change this if it is no longer true.
- bool isFuncNoUnwind() const { return true;}
- bool isSPIRVCmpInstTransToLLVMInst(SPIRVInstruction *BI) const;
- bool transOCLBuiltinsFromVariables();
- bool transOCLBuiltinFromVariable(GlobalVariable *GV,
- SPIRVBuiltinVariableKind Kind);
- MDString *transOCLKernelArgTypeName(SPIRVFunctionParameter *);
-
- Value *mapFunction(SPIRVFunction *BF, Function *F) {
- SPIRVDBG(spvdbgs() << "[mapFunction] " << *BF << " -> ";
- dbgs() << *F << '\n';)
- FuncMap[BF] = F;
- return F;
- }
-
- Value *getTranslatedValue(SPIRVValue *BV);
- Type *getTranslatedType(SPIRVType *BT);
- IntrinsicInst *getLifetimeStartIntrinsic(Instruction *I);
-
- SPIRVErrorLog &getErrorLog() {
- return BM->getErrorLog();
- }
-
- void setCallingConv(CallInst *Call) {
- Function *F = Call->getCalledFunction();
- assert(F);
- Call->setCallingConv(F->getCallingConv());
- }
-
- void setAttrByCalledFunc(CallInst *Call);
- Type *transFPType(SPIRVType* T);
- BinaryOperator *transShiftLogicalBitwiseInst(SPIRVValue* BV, BasicBlock* BB,
- Function* F);
- void transFlags(llvm::Value* V);
- Instruction *transCmpInst(SPIRVValue* BV, BasicBlock* BB, Function* F);
- void transOCLBuiltinFromInstPreproc(SPIRVInstruction* BI, Type *&RetTy,
- std::vector<SPIRVValue *> &Args);
- Instruction* transOCLBuiltinPostproc(SPIRVInstruction* BI,
- CallInst* CI, BasicBlock* BB, const std::string &DemangledName);
- std::string transOCLImageTypeName(SPIRV::SPIRVTypeImage* ST);
- std::string transOCLSampledImageTypeName(SPIRV::SPIRVTypeSampledImage* ST);
- std::string transOCLPipeTypeName(SPIRV::SPIRVTypePipe* ST,
- bool UseSPIRVFriendlyFormat = false, int PipeAccess = 0);
- std::string transOCLPipeStorageTypeName(SPIRV::SPIRVTypePipeStorage* PST);
- std::string transOCLImageTypeAccessQualifier(SPIRV::SPIRVTypeImage* ST);
- std::string transOCLPipeTypeAccessQualifier(SPIRV::SPIRVTypePipe* ST);
-
- Value *oclTransConstantSampler(SPIRV::SPIRVConstantSampler* BCS);
- Value * oclTransConstantPipeStorage(SPIRV::SPIRVConstantPipeStorage* BCPS);
- void setName(llvm::Value* V, SPIRVValue* BV);
- void setLLVMLoopMetadata(SPIRVLoopMerge* LM, BranchInst* BI);
- void insertImageNameAccessQualifier(SPIRV::SPIRVTypeImage* ST, std::string &Name);
- template<class Source, class Func>
- bool foreachFuncCtlMask(Source, Func);
- llvm::GlobalValue::LinkageTypes transLinkageType(const SPIRVValue* V);
- Instruction *transOCLAllAny(SPIRVInstruction* BI, BasicBlock *BB);
- Instruction *transOCLRelational(SPIRVInstruction* BI, BasicBlock *BB);
-
- CallInst *transOCLBarrier(BasicBlock *BB, SPIRVWord ExecScope,
- SPIRVWord MemSema, SPIRVWord MemScope);
-
- CallInst *transOCLMemFence(BasicBlock *BB,
- SPIRVWord MemSema, SPIRVWord MemScope);
-};
-
-Type *
-SPIRVToLLVM::getTranslatedType(SPIRVType *BV){
- auto Loc = TypeMap.find(BV);
- if (Loc != TypeMap.end())
- return Loc->second;
- return nullptr;
-}
-
-Value *
-SPIRVToLLVM::getTranslatedValue(SPIRVValue *BV){
- auto Loc = ValueMap.find(BV);
- if (Loc != ValueMap.end())
- return Loc->second;
- return nullptr;
-}
-
-IntrinsicInst *
-SPIRVToLLVM::getLifetimeStartIntrinsic(Instruction *I) {
- auto II = dyn_cast<IntrinsicInst>(I);
- if (II && II->getIntrinsicID() == Intrinsic::lifetime_start)
- return II;
- // Bitcast might be inserted during translation of OpLifetimeStart
- auto BC = dyn_cast<BitCastInst>(I);
- if (BC) {
- for (const auto &U : BC->users()) {
- II = dyn_cast<IntrinsicInst>(U);
- if (II && II->getIntrinsicID() == Intrinsic::lifetime_start)
- return II;;
- }
- }
- return nullptr;
-}
-
-void
-SPIRVToLLVM::setAttrByCalledFunc(CallInst *Call) {
- Function *F = Call->getCalledFunction();
- assert(F);
- if (F->isIntrinsic()) {
- return;
- }
- Call->setCallingConv(F->getCallingConv());
- Call->setAttributes(F->getAttributes());
-}
-
-bool
-SPIRVToLLVM::transOCLBuiltinsFromVariables(){
- std::vector<GlobalVariable *> WorkList;
- for (auto I = M->global_begin(), E = M->global_end(); I != E; ++I) {
- SPIRVBuiltinVariableKind Kind;
- if (!isSPIRVBuiltinVariable(&(*I), &Kind))
- continue;
- if (!transOCLBuiltinFromVariable(&(*I), Kind))
- return false;
- WorkList.push_back(&(*I));
- }
- for (auto &I:WorkList) {
- I->eraseFromParent();
- }
- return true;
-}
-
-// For integer types shorter than 32 bit, unsigned/signedness can be inferred
-// from zext/sext attribute.
-MDString *
-SPIRVToLLVM::transOCLKernelArgTypeName(SPIRVFunctionParameter *Arg) {
- auto Ty = Arg->isByVal() ? Arg->getType()->getPointerElementType() :
- Arg->getType();
- return MDString::get(*Context, transTypeToOCLTypeName(Ty, !Arg->isZext()));
-}
-
-// Variable like GlobalInvolcationId[x] -> get_global_id(x).
-// Variable like WorkDim -> get_work_dim().
-bool
-SPIRVToLLVM::transOCLBuiltinFromVariable(GlobalVariable *GV,
- SPIRVBuiltinVariableKind Kind) {
- std::string FuncName = SPIRSPIRVBuiltinVariableMap::rmap(Kind);
- std::string MangledName;
- Type *ReturnTy = GV->getType()->getPointerElementType();
- bool IsVec = ReturnTy->isVectorTy();
- if (IsVec)
- ReturnTy = cast<VectorType>(ReturnTy)->getElementType();
- std::vector<Type*> ArgTy;
- if (IsVec)
- ArgTy.push_back(Type::getInt32Ty(*Context));
- MangleOpenCLBuiltin(FuncName, ArgTy, MangledName);
- Function *Func = M->getFunction(MangledName);
- if (!Func) {
- FunctionType *FT = FunctionType::get(ReturnTy, ArgTy, false);
- Func = Function::Create(FT, GlobalValue::ExternalLinkage, MangledName, M);
- Func->setCallingConv(CallingConv::SPIR_FUNC);
- Func->addFnAttr(Attribute::NoUnwind);
- Func->addFnAttr(Attribute::ReadNone);
- }
- std::vector<Instruction *> Deletes;
- std::vector<Instruction *> Uses;
- for (auto UI = GV->user_begin(), UE = GV->user_end(); UI != UE; ++UI) {
- assert (isa<LoadInst>(*UI) && "Unsupported use");
- auto LD = dyn_cast<LoadInst>(*UI);
- if (!IsVec) {
- Uses.push_back(LD);
- Deletes.push_back(LD);
- continue;
- }
- for (auto LDUI = LD->user_begin(), LDUE = LD->user_end(); LDUI != LDUE;
- ++LDUI) {
- assert(isa<ExtractElementInst>(*LDUI) && "Unsupported use");
- auto EEI = dyn_cast<ExtractElementInst>(*LDUI);
- Uses.push_back(EEI);
- Deletes.push_back(EEI);
- }
- Deletes.push_back(LD);
- }
- for (auto &I:Uses) {
- std::vector<Value *> Arg;
- if (auto EEI = dyn_cast<ExtractElementInst>(I))
- Arg.push_back(EEI->getIndexOperand());
- auto Call = CallInst::Create(Func, Arg, "", I);
- Call->takeName(I);
- setAttrByCalledFunc(Call);
- SPIRVDBG(dbgs() << "[transOCLBuiltinFromVariable] " << *I << " -> " <<
- *Call << '\n';)
- I->replaceAllUsesWith(Call);
- }
- for (auto &I:Deletes) {
- I->eraseFromParent();
- }
- return true;
-}
-
-Type *
-SPIRVToLLVM::transFPType(SPIRVType* T) {
- switch(T->getFloatBitWidth()) {
- case 16: return Type::getHalfTy(*Context);
- case 32: return Type::getFloatTy(*Context);
- case 64: return Type::getDoubleTy(*Context);
- default:
- llvm_unreachable("Invalid type");
- return nullptr;
- }
-}
-
-std::string
-SPIRVToLLVM::transOCLImageTypeName(SPIRV::SPIRVTypeImage* ST) {
- std::string Name = std::string(kSPR2TypeName::OCLPrefix)
- + rmap<std::string>(ST->getDescriptor());
- if (SPIRVGenImgTypeAccQualPostfix)
- SPIRVToLLVM::insertImageNameAccessQualifier(ST, Name);
- return std::move(Name);
-}
-
-std::string
-SPIRVToLLVM::transOCLSampledImageTypeName(SPIRV::SPIRVTypeSampledImage* ST) {
- return getSPIRVTypeName(kSPIRVTypeName::SampledImg,
- getSPIRVImageTypePostfixes(getSPIRVImageSampledTypeName(
- ST->getImageType()->getSampledType()),
- ST->getImageType()->getDescriptor(),
- ST->getImageType()->hasAccessQualifier() ?
- ST->getImageType()->getAccessQualifier() :
- AccessQualifierReadOnly));
-}
-
-std::string
-SPIRVToLLVM::transOCLPipeTypeName(SPIRV::SPIRVTypePipe* PT,
- bool UseSPIRVFriendlyFormat, int PipeAccess){
- if (!UseSPIRVFriendlyFormat)
- return kSPR2TypeName::Pipe;
- else
- return std::string(kSPIRVTypeName::PrefixAndDelim)
- + kSPIRVTypeName::Pipe
- + kSPIRVTypeName::Delimiter
- + kSPIRVTypeName::PostfixDelim
- + PipeAccess;
-}
-
-std::string
-SPIRVToLLVM::transOCLPipeStorageTypeName(SPIRV::SPIRVTypePipeStorage* PST) {
- return std::string(kSPIRVTypeName::PrefixAndDelim)
- + kSPIRVTypeName::PipeStorage;
-}
-
-Type *
-SPIRVToLLVM::transType(SPIRVType *T, bool IsClassMember) {
- auto Loc = TypeMap.find(T);
- if (Loc != TypeMap.end())
- return Loc->second;
-
- SPIRVDBG(spvdbgs() << "[transType] " << *T << " -> ";)
- T->validate();
- switch(T->getOpCode()) {
- case OpTypeVoid:
- return mapType(T, Type::getVoidTy(*Context));
- case OpTypeBool:
- return mapType(T, Type::getInt1Ty(*Context));
- case OpTypeInt:
- return mapType(T, Type::getIntNTy(*Context, T->getIntegerBitWidth()));
- case OpTypeFloat:
- return mapType(T, transFPType(T));
- case OpTypeArray:
- return mapType(T, ArrayType::get(transType(T->getArrayElementType()),
- T->getArrayLength()));
- case OpTypePointer:
- return mapType(T, PointerType::get(transType(
- T->getPointerElementType(), IsClassMember),
- SPIRSPIRVAddrSpaceMap::rmap(T->getPointerStorageClass())));
- case OpTypeVector:
- return mapType(T, VectorType::get(transType(T->getVectorComponentType()),
- T->getVectorComponentCount()));
- case OpTypeOpaque:
- return mapType(T, StructType::create(*Context, T->getName()));
- case OpTypeFunction: {
- auto FT = static_cast<SPIRVTypeFunction *>(T);
- auto RT = transType(FT->getReturnType());
- std::vector<Type *> PT;
- for (size_t I = 0, E = FT->getNumParameters(); I != E; ++I)
- PT.push_back(transType(FT->getParameterType(I)));
- return mapType(T, FunctionType::get(RT, PT, false));
- }
- case OpTypeImage: {
- auto ST = static_cast<SPIRVTypeImage *>(T);
- if (ST->isOCLImage())
- return mapType(T, getOrCreateOpaquePtrType(M,
- transOCLImageTypeName(ST)));
- else
- llvm_unreachable("Unsupported image type");
- return nullptr;
- }
- case OpTypeSampler:
- return mapType(T, Type::getInt32Ty(*Context));
- case OpTypeSampledImage: {
- auto ST = static_cast<SPIRVTypeSampledImage *>(T);
- return mapType(T, getOrCreateOpaquePtrType(M,
- transOCLSampledImageTypeName(ST)));
- }
- case OpTypeStruct: {
- auto ST = static_cast<SPIRVTypeStruct *>(T);
- auto Name = ST->getName();
- if (!Name.empty()) {
- if (auto OldST = M->getTypeByName(Name))
- OldST->setName("");
- }
- auto *StructTy = StructType::create(*Context, Name);
- mapType(ST, StructTy);
- SmallVector<Type *, 4> MT;
- for (size_t I = 0, E = ST->getMemberCount(); I != E; ++I)
- MT.push_back(transType(ST->getMemberType(I), true));
- StructTy->setBody(MT, ST->isPacked());
- return StructTy;
- }
- case OpTypePipe: {
- auto PT = static_cast<SPIRVTypePipe *>(T);
- return mapType(T, getOrCreateOpaquePtrType(M,
- transOCLPipeTypeName(PT, IsClassMember, PT->getAccessQualifier()),
- getOCLOpaqueTypeAddrSpace(T->getOpCode())));
-
- }
- case OpTypePipeStorage: {
- auto PST = static_cast<SPIRVTypePipeStorage *>(T);
- return mapType(T, getOrCreateOpaquePtrType(M,
- transOCLPipeStorageTypeName(PST),
- getOCLOpaqueTypeAddrSpace(T->getOpCode())));
- }
- default: {
- auto OC = T->getOpCode();
- if (isOpaqueGenericTypeOpCode(OC))
- return mapType(T, getOrCreateOpaquePtrType(M,
- OCLOpaqueTypeOpCodeMap::rmap(OC),
- getOCLOpaqueTypeAddrSpace(OC)));
- llvm_unreachable("Not implemented");
- }
- }
- return 0;
-}
-
-
-std::string
-SPIRVToLLVM::transTypeToOCLTypeName(SPIRVType *T, bool IsSigned) {
- switch(T->getOpCode()) {
- case OpTypeVoid:
- return "void";
- case OpTypeBool:
- return "bool";
- case OpTypeInt: {
- std::string Prefix = IsSigned ? "" : "u";
- switch(T->getIntegerBitWidth()) {
- case 8:
- return Prefix + "char";
- case 16:
- return Prefix + "short";
- case 32:
- return Prefix + "int";
- case 64:
- return Prefix + "long";
- default:
- llvm_unreachable("invalid integer size");
- return Prefix + std::string("int") + T->getIntegerBitWidth() + "_t";
- }
- }
- break;
- case OpTypeFloat:
- switch(T->getFloatBitWidth()){
- case 16:
- return "half";
- case 32:
- return "float";
- case 64:
- return "double";
- default:
- llvm_unreachable("invalid floating pointer bitwidth");
- return std::string("float") + T->getFloatBitWidth() + "_t";
- }
- break;
- case OpTypeArray:
- return "array";
- case OpTypePointer:
- return transTypeToOCLTypeName(T->getPointerElementType()) + "*";
- case OpTypeVector:
- return transTypeToOCLTypeName(T->getVectorComponentType()) +
- T->getVectorComponentCount();
- case OpTypeOpaque:
- return T->getName();
- case OpTypeFunction:
- llvm_unreachable("Unsupported");
- return "function";
- case OpTypeStruct: {
- auto Name = T->getName();
- if (Name.find("struct.") == 0)
- Name[6] = ' ';
- else if (Name.find("union.") == 0)
- Name[5] = ' ';
- return Name;
- }
- case OpTypePipe:
- return "pipe";
- case OpTypeSampler:
- return "sampler_t";
- case OpTypeImage: {
- std::string Name;
- Name = rmap<std::string>(static_cast<SPIRVTypeImage *>(T)->getDescriptor());
- if (SPIRVGenImgTypeAccQualPostfix) {
- auto ST = static_cast<SPIRVTypeImage *>(T);
- insertImageNameAccessQualifier(ST, Name);
- }
- return Name;
- }
- default:
- if (isOpaqueGenericTypeOpCode(T->getOpCode())) {
- return OCLOpaqueTypeOpCodeMap::rmap(T->getOpCode());
- }
- llvm_unreachable("Not implemented");
- return "unknown";
- }
-}
-
-std::vector<Type *>
-SPIRVToLLVM::transTypeVector(const std::vector<SPIRVType *> &BT) {
- std::vector<Type *> T;
- for (auto I: BT)
- T.push_back(transType(I));
- return T;
-}
-
-std::vector<Value *>
-SPIRVToLLVM::transValue(const std::vector<SPIRVValue *> &BV, Function *F,
- BasicBlock *BB) {
- std::vector<Value *> V;
- for (auto I: BV)
- V.push_back(transValue(I, F, BB));
- return V;
-}
-
-bool
-SPIRVToLLVM::isSPIRVCmpInstTransToLLVMInst(SPIRVInstruction* BI) const {
- auto OC = BI->getOpCode();
- return isCmpOpCode(OC) &&
- !(OC >= OpLessOrGreater && OC <= OpUnordered);
-}
-
-void
-SPIRVToLLVM::transFlags(llvm::Value* V) {
- if(!isa<Instruction>(V))
- return;
- auto OC = cast<Instruction>(V)->getOpcode();
- if (OC == Instruction::AShr || OC == Instruction::LShr) {
- cast<BinaryOperator>(V)->setIsExact();
- return;
- }
-}
-
-void
-SPIRVToLLVM::setName(llvm::Value* V, SPIRVValue* BV) {
- auto Name = BV->getName();
- if (!Name.empty() && (!V->hasName() || Name != V->getName()))
- V->setName(Name);
-}
-
-void
-SPIRVToLLVM::setLLVMLoopMetadata(SPIRVLoopMerge* LM, BranchInst* BI) {
- if (!LM)
- return;
- llvm::MDString *Name = nullptr;
- auto Temp = MDNode::getTemporary(*Context, None);
- auto Self = MDNode::get(*Context, Temp.get());
- Self->replaceOperandWith(0, Self);
-
- if (LM->getLoopControl() == LoopControlMaskNone) {
- BI->setMetadata("llvm.loop", Self);
- return;
- }
- else if(LM->getLoopControl() == LoopControlUnrollMask)
- Name = llvm::MDString::get(*Context, "llvm.loop.unroll.full");
- else if (LM->getLoopControl() == LoopControlDontUnrollMask)
- Name = llvm::MDString::get(*Context, "llvm.loop.unroll.disable");
- else
- return;
-
- std::vector<llvm::Metadata *> OpValues(1, Name);
- SmallVector<llvm::Metadata *, 2> Metadata;
- Metadata.push_back(llvm::MDNode::get(*Context, Self));
- Metadata.push_back(llvm::MDNode::get(*Context, OpValues));
-
- llvm::MDNode *Node = llvm::MDNode::get(*Context, Metadata);
- Node->replaceOperandWith(0, Node);
- BI->setMetadata("llvm.loop", Node);
-}
-
-void SPIRVToLLVM::insertImageNameAccessQualifier(SPIRV::SPIRVTypeImage* ST, std::string &Name) {
- std::string QName = rmap<std::string>(ST->getAccessQualifier());
- // transform: read_only -> ro, write_only -> wo, read_write -> rw
- QName = QName.substr(0,1) + QName.substr(QName.find("_") + 1, 1) + "_";
- assert(!Name.empty() && "image name should not be empty");
- Name.insert(Name.size() - 1, QName);
-}
-
-Value *
-SPIRVToLLVM::transValue(SPIRVValue *BV, Function *F, BasicBlock *BB,
- bool CreatePlaceHolder){
- SPIRVToLLVMValueMap::iterator Loc = ValueMap.find(BV);
- if (Loc != ValueMap.end() && (!PlaceholderMap.count(BV) || CreatePlaceHolder))
- return Loc->second;
-
- SPIRVDBG(spvdbgs() << "[transValue] " << *BV << " -> ";)
- BV->validate();
-
- auto V = transValueWithoutDecoration(BV, F, BB, CreatePlaceHolder);
- if (!V) {
- SPIRVDBG(dbgs() << " Warning ! nullptr\n";)
- return nullptr;
- }
- setName(V, BV);
- if (!transDecoration(BV, V)) {
- assert (0 && "trans decoration fail");
- return nullptr;
- }
- transFlags(V);
-
- SPIRVDBG(dbgs() << *V << '\n';)
-
- return V;
-}
-
-Value *
-SPIRVToLLVM::transDeviceEvent(SPIRVValue *BV, Function *F, BasicBlock *BB) {
- auto Val = transValue(BV, F, BB, false);
- auto Ty = dyn_cast<PointerType>(Val->getType());
- assert(Ty && "Invalid Device Event");
- if (Ty->getAddressSpace() == SPIRAS_Generic)
- return Val;
-
- IRBuilder<> Builder(BB);
- auto EventTy = PointerType::get(Ty->getElementType(), SPIRAS_Generic);
- return Builder.CreateAddrSpaceCast(Val, EventTy);
-}
-
-Value *
-SPIRVToLLVM::transConvertInst(SPIRVValue* BV, Function* F, BasicBlock* BB) {
- SPIRVUnary* BC = static_cast<SPIRVUnary*>(BV);
- auto Src = transValue(BC->getOperand(0), F, BB, BB ? true : false);
- auto Dst = transType(BC->getType());
- CastInst::CastOps CO = Instruction::BitCast;
- bool IsExt = Dst->getScalarSizeInBits()
- > Src->getType()->getScalarSizeInBits();
- switch (BC->getOpCode()) {
- case OpPtrCastToGeneric:
- case OpGenericCastToPtr:
- CO = Instruction::AddrSpaceCast;
- break;
- case OpSConvert:
- CO = IsExt ? Instruction::SExt : Instruction::Trunc;
- break;
- case OpUConvert:
- CO = IsExt ? Instruction::ZExt : Instruction::Trunc;
- break;
- case OpFConvert:
- CO = IsExt ? Instruction::FPExt : Instruction::FPTrunc;
- break;
- default:
- CO = static_cast<CastInst::CastOps>(OpCodeMap::rmap(BC->getOpCode()));
- }
- assert(CastInst::isCast(CO) && "Invalid cast op code");
- SPIRVDBG(if (!CastInst::castIsValid(CO, Src, Dst)) {
- spvdbgs() << "Invalid cast: " << *BV << " -> ";
- dbgs() << "Op = " << CO << ", Src = " << *Src << " Dst = " << *Dst << '\n';
- })
- if (BB)
- return CastInst::Create(CO, Src, Dst, BV->getName(), BB);
- return ConstantExpr::getCast(CO, dyn_cast<Constant>(Src), Dst);
-}
-
-BinaryOperator *SPIRVToLLVM::transShiftLogicalBitwiseInst(SPIRVValue* BV,
- BasicBlock* BB,Function* F) {
- SPIRVBinary* BBN = static_cast<SPIRVBinary*>(BV);
- assert(BB && "Invalid BB");
- Instruction::BinaryOps BO;
- auto OP = BBN->getOpCode();
- if (isLogicalOpCode(OP))
- OP = IntBoolOpMap::rmap(OP);
- BO = static_cast<Instruction::BinaryOps>(OpCodeMap::rmap(OP));
- auto Inst = BinaryOperator::Create(BO,
- transValue(BBN->getOperand(0), F, BB),
- transValue(BBN->getOperand(1), F, BB), BV->getName(), BB);
- return Inst;
-}
-
-Instruction *
-SPIRVToLLVM::transCmpInst(SPIRVValue* BV, BasicBlock* BB, Function* F) {
- SPIRVCompare* BC = static_cast<SPIRVCompare*>(BV);
- assert(BB && "Invalid BB");
- SPIRVType* BT = BC->getOperand(0)->getType();
- Instruction* Inst = nullptr;
- auto OP = BC->getOpCode();
- if (isLogicalOpCode(OP))
- OP = IntBoolOpMap::rmap(OP);
- if (BT->isTypeVectorOrScalarInt() || BT->isTypeVectorOrScalarBool() ||
- BT->isTypePointer())
- Inst = new ICmpInst(*BB, CmpMap::rmap(OP),
- transValue(BC->getOperand(0), F, BB),
- transValue(BC->getOperand(1), F, BB));
- else if (BT->isTypeVectorOrScalarFloat())
- Inst = new FCmpInst(*BB, CmpMap::rmap(OP),
- transValue(BC->getOperand(0), F, BB),
- transValue(BC->getOperand(1), F, BB));
- assert(Inst && "not implemented");
- return Inst;
-}
-
-bool
-SPIRVToLLVM::postProcessOCL() {
- std::string DemangledName;
- SPIRVWord SrcLangVer = 0;
- BM->getSourceLanguage(&SrcLangVer);
- bool isCPP = SrcLangVer == kOCLVer::CL21;
- for (auto I = M->begin(), E = M->end(); I != E;) {
- auto F = I++;
- if (F->hasName() && F->isDeclaration()) {
- DEBUG(dbgs() << "[postProcessOCL sret] " << *F << '\n');
- if (F->getReturnType()->isStructTy() &&
- oclIsBuiltin(F->getName(), &DemangledName, isCPP)) {
- if (!postProcessOCLBuiltinReturnStruct(&(*F)))
- return false;
- }
- }
- }
- for (auto I = M->begin(), E = M->end(); I != E;) {
- auto F = I++;
- if (F->hasName() && F->isDeclaration()) {
- DEBUG(dbgs() << "[postProcessOCL array arg] " << *F << '\n');
- if (hasArrayArg(&(*F)) && oclIsBuiltin(F->getName(), &DemangledName, isCPP))
- if (!postProcessOCLBuiltinWithArrayArguments(&(*F), DemangledName))
- return false;
- }
- }
- return true;
-}
-
-bool
-SPIRVToLLVM::postProcessOCLBuiltinReturnStruct(Function *F) {
- std::string Name = F->getName();
- F->setName(Name + ".old");
- for (auto I = F->user_begin(), E = F->user_end(); I != E;) {
- if (auto CI = dyn_cast<CallInst>(*I++)) {
- auto ST = dyn_cast<StoreInst>(*(CI->user_begin()));
- assert(ST);
- std::vector<Type *> ArgTys;
- getFunctionTypeParameterTypes(F->getFunctionType(), ArgTys);
- ArgTys.insert(ArgTys.begin(), PointerType::get(F->getReturnType(),
- SPIRAS_Private));
- auto newF = getOrCreateFunction(M, Type::getVoidTy(*Context),
- ArgTys, Name);
- newF->setCallingConv(F->getCallingConv());
- auto Args = getArguments(CI);
- Args.insert(Args.begin(), ST->getPointerOperand());
- auto NewCI = CallInst::Create(newF, Args, CI->getName(), CI);
- NewCI->setCallingConv(CI->getCallingConv());
- ST->eraseFromParent();
- CI->eraseFromParent();
- }
- }
- F->eraseFromParent();
- return true;
-}
-
-bool
-SPIRVToLLVM::postProcessOCLBuiltinWithArrayArguments(Function* F,
- const std::string &DemangledName) {
- DEBUG(dbgs() << "[postProcessOCLBuiltinWithArrayArguments] " << *F << '\n');
- auto Attrs = F->getAttributes();
- auto Name = F->getName();
- mutateFunction(F, [=](CallInst *CI, std::vector<Value *> &Args) {
- auto FBegin = CI->getParent()->getParent()->begin()->getFirstInsertionPt();
- for (auto &I:Args) {
- auto T = I->getType();
- if (!T->isArrayTy())
- continue;
- auto Alloca = new AllocaInst(T, 0, "", &(*FBegin));
- new StoreInst(I, Alloca, false, CI);
- auto Zero = ConstantInt::getNullValue(Type::getInt32Ty(T->getContext()));
- Value *Index[] = {Zero, Zero};
- I = GetElementPtrInst::CreateInBounds(Alloca, Index, "", CI);
- }
- return Name;
- }, nullptr, &Attrs);
- return true;
-}
-
-// ToDo: Handle unsigned integer return type. May need spec change.
-Instruction *
-SPIRVToLLVM::postProcessOCLReadImage(SPIRVInstruction *BI, CallInst* CI,
- const std::string &FuncName) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- StringRef ImageTypeName;
- bool isDepthImage = false;
- if (isOCLImageType(
- (cast<CallInst>(CI->getOperand(0)))->getArgOperand(0)->getType(),
- &ImageTypeName))
- isDepthImage = ImageTypeName.endswith("depth_t");
- return mutateCallInstOCL(
- M, CI,
- [=](CallInst *, std::vector<Value *> &Args, llvm::Type *&RetTy) {
- CallInst *CallSampledImg = cast<CallInst>(Args[0]);
- auto Img = CallSampledImg->getArgOperand(0);
- assert(isOCLImageType(Img->getType()));
- auto Sampler = CallSampledImg->getArgOperand(1);
- Args[0] = Img;
- Args.insert(Args.begin() + 1, Sampler);
- if(Args.size() > 4 ) {
- ConstantInt* ImOp = dyn_cast<ConstantInt>(Args[3]);
- ConstantFP* LodVal = dyn_cast<ConstantFP>(Args[4]);
- // Drop "Image Operands" argument.
- Args.erase(Args.begin() + 3, Args.begin() + 4);
- // If the image operand is LOD and its value is zero, drop it too.
- if (ImOp && LodVal && LodVal->isNullValue() &&
- ImOp->getZExtValue() == ImageOperandsMask::ImageOperandsLodMask )
- Args.erase(Args.begin() + 3, Args.end());
- }
- if (CallSampledImg->hasOneUse()) {
- CallSampledImg->replaceAllUsesWith(
- UndefValue::get(CallSampledImg->getType()));
- CallSampledImg->dropAllReferences();
- CallSampledImg->eraseFromParent();
- }
- Type *T = CI->getType();
- if (auto VT = dyn_cast<VectorType>(T))
- T = VT->getElementType();
- RetTy = isDepthImage ? T : CI->getType();
- return std::string(kOCLBuiltinName::SampledReadImage) +
- (T->isFloatingPointTy() ? 'f' : 'i');
- },
- [=](CallInst *NewCI) -> Instruction * {
- if (isDepthImage)
- return InsertElementInst::Create(
- UndefValue::get(VectorType::get(NewCI->getType(), 4)), NewCI,
- getSizet(M, 0), "", NewCI->getParent());
- return NewCI;
- },
- &Attrs);
-}
-
-CallInst*
-SPIRVToLLVM::postProcessOCLWriteImage(SPIRVInstruction *BI, CallInst *CI,
- const std::string &DemangledName) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- return mutateCallInstOCL(M, CI, [=](CallInst *, std::vector<Value *> &Args) {
- llvm::Type *T = Args[2]->getType();
- if (Args.size() > 4) {
- ConstantInt* ImOp = dyn_cast<ConstantInt>(Args[3]);
- ConstantFP* LodVal = dyn_cast<ConstantFP>(Args[4]);
- // Drop "Image Operands" argument.
- Args.erase(Args.begin() + 3, Args.begin() + 4);
- // If the image operand is LOD and its value is zero, drop it too.
- if (ImOp && LodVal && LodVal->isNullValue() &&
- ImOp->getZExtValue() == ImageOperandsMask::ImageOperandsLodMask )
- Args.erase(Args.begin() + 3, Args.end());
- else
- std::swap(Args[2], Args[3]);
- }
- return std::string(kOCLBuiltinName::WriteImage) +
- (T->isFPOrFPVectorTy() ? 'f' : 'i');
- }, &Attrs);
-}
-
-CallInst *
-SPIRVToLLVM::postProcessOCLBuildNDRange(SPIRVInstruction *BI, CallInst *CI,
- const std::string &FuncName) {
- assert(CI->getNumArgOperands() == 3);
- auto GWS = CI->getArgOperand(0);
- auto LWS = CI->getArgOperand(1);
- auto GWO = CI->getArgOperand(2);
- CI->setArgOperand(0, GWO);
- CI->setArgOperand(1, GWS);
- CI->setArgOperand(2, LWS);
- return CI;
-}
-
-Instruction *
-SPIRVToLLVM::postProcessGroupAllAny(CallInst *CI,
- const std::string &DemangledName) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- return mutateCallInstSPIRV(
- M, CI,
- [=](CallInst *, std::vector<Value *> &Args, llvm::Type *&RetTy) {
- Type *Int32Ty = Type::getInt32Ty(*Context);
- RetTy = Int32Ty;
- Args[1] = CastInst::CreateZExtOrBitCast(Args[1], Int32Ty, "", CI);
- return DemangledName;
- },
- [=](CallInst *NewCI) -> Instruction * {
- Type *RetTy = Type::getInt1Ty(*Context);
- return CastInst::CreateTruncOrBitCast(NewCI, RetTy, "",
- NewCI->getNextNode());
- },
- &Attrs);
-}
-
-CallInst *
-SPIRVToLLVM::expandOCLBuiltinWithScalarArg(CallInst* CI,
- const std::string &FuncName) {
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- if (!CI->getOperand(0)->getType()->isVectorTy() &&
- CI->getOperand(1)->getType()->isVectorTy()) {
- return mutateCallInstOCL(M, CI, [=](CallInst *, std::vector<Value *> &Args){
- unsigned vecSize = CI->getOperand(1)->getType()->getVectorNumElements();
- Value *NewVec = nullptr;
- if (auto CA = dyn_cast<Constant>(Args[0]))
- NewVec = ConstantVector::getSplat(vecSize, CA);
- else {
- NewVec = ConstantVector::getSplat(vecSize,
- Constant::getNullValue(Args[0]->getType()));
- NewVec = InsertElementInst::Create(NewVec, Args[0], getInt32(M, 0), "",
- CI);
- NewVec = new ShuffleVectorInst(NewVec, NewVec,
- ConstantVector::getSplat(vecSize, getInt32(M, 0)), "", CI);
- }
- NewVec->takeName(Args[0]);
- Args[0] = NewVec;
- return FuncName;
- }, &Attrs);
- }
- return CI;
-}
-
-std::string
-SPIRVToLLVM::transOCLPipeTypeAccessQualifier(SPIRV::SPIRVTypePipe* ST) {
- return SPIRSPIRVAccessQualifierMap::rmap(ST->getAccessQualifier());
-}
-
-void
-SPIRVToLLVM::transGeneratorMD() {
- SPIRVMDBuilder B(*M);
- B.addNamedMD(kSPIRVMD::Generator)
- .addOp()
- .addU16(BM->getGeneratorId())
- .addU16(BM->getGeneratorVer())
- .done();
-}
-
-Value *
-SPIRVToLLVM::oclTransConstantSampler(SPIRV::SPIRVConstantSampler* BCS) {
- auto Lit = (BCS->getAddrMode() << 1) |
- BCS->getNormalized() |
- ((BCS->getFilterMode() + 1) << 4);
- auto Ty = IntegerType::getInt32Ty(*Context);
- return ConstantInt::get(Ty, Lit);
-}
-
-Value *
-SPIRVToLLVM::oclTransConstantPipeStorage(
- SPIRV::SPIRVConstantPipeStorage* BCPS) {
-
- string CPSName = string(kSPIRVTypeName::PrefixAndDelim)
- + kSPIRVTypeName::ConstantPipeStorage;
-
- auto Int32Ty = IntegerType::getInt32Ty(*Context);
- auto CPSTy = M->getTypeByName(CPSName);
- if (!CPSTy) {
- Type* CPSElemsTy[] = { Int32Ty, Int32Ty, Int32Ty };
- CPSTy = StructType::create(*Context, CPSElemsTy, CPSName);
- }
-
- assert(CPSTy != nullptr && "Could not create spirv.ConstantPipeStorage");
-
- Constant* CPSElems[] = {
- ConstantInt::get(Int32Ty, BCPS->getPacketSize()),
- ConstantInt::get(Int32Ty, BCPS->getPacketAlign()),
- ConstantInt::get(Int32Ty, BCPS->getCapacity())
- };
-
- return new GlobalVariable(*M, CPSTy, false, GlobalValue::LinkOnceODRLinkage,
- ConstantStruct::get(CPSTy, CPSElems), BCPS->getName(),
- nullptr, GlobalValue::NotThreadLocal, SPIRAS_Global);
-}
-
-/// For instructions, this function assumes they are created in order
-/// and appended to the given basic block. An instruction may use a
-/// instruction from another BB which has not been translated. Such
-/// instructions should be translated to place holders at the point
-/// of first use, then replaced by real instructions when they are
-/// created.
-///
-/// When CreatePlaceHolder is true, create a load instruction of a
-/// global variable as placeholder for SPIRV instruction. Otherwise,
-/// create instruction and replace placeholder if there is one.
-Value *
-SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
- BasicBlock *BB, bool CreatePlaceHolder){
-
- auto OC = BV->getOpCode();
- IntBoolOpMap::rfind(OC, &OC);
-
- // Translation of non-instruction values
- switch(OC) {
- case OpConstant: {
- SPIRVConstant *BConst = static_cast<SPIRVConstant *>(BV);
- SPIRVType *BT = BV->getType();
- Type *LT = transType(BT);
- switch(BT->getOpCode()) {
- case OpTypeBool:
- case OpTypeInt:
- return mapValue(BV, ConstantInt::get(LT, BConst->getZExtIntValue(),
- static_cast<SPIRVTypeInt*>(BT)->isSigned()));
- case OpTypeFloat: {
- const llvm::fltSemantics *FS = nullptr;
- switch (BT->getFloatBitWidth()) {
- case 16:
- FS = &APFloat::IEEEhalf();
- break;
- case 32:
- FS = &APFloat::IEEEsingle();
- break;
- case 64:
- FS = &APFloat::IEEEdouble();
- break;
- default:
- llvm_unreachable("invalid float type");
- }
- return mapValue(BV, ConstantFP::get(*Context, APFloat(*FS,
- APInt(BT->getFloatBitWidth(), BConst->getZExtIntValue()))));
- }
- default:
- llvm_unreachable("Not implemented");
- return nullptr;
- }
- }
-
- case OpConstantTrue:
- return mapValue(BV, ConstantInt::getTrue(*Context));
-
- case OpConstantFalse:
- return mapValue(BV, ConstantInt::getFalse(*Context));
-
- case OpConstantNull: {
- auto LT = transType(BV->getType());
- return mapValue(BV, Constant::getNullValue(LT));
- }
-
- case OpConstantComposite: {
- auto BCC = static_cast<SPIRVConstantComposite*>(BV);
- std::vector<Constant *> CV;
- for (auto &I:BCC->getElements())
- CV.push_back(dyn_cast<Constant>(transValue(I, F, BB)));
- switch(BV->getType()->getOpCode()) {
- case OpTypeVector:
- return mapValue(BV, ConstantVector::get(CV));
- case OpTypeArray:
- return mapValue(BV, ConstantArray::get(
- dyn_cast<ArrayType>(transType(BCC->getType())), CV));
- case OpTypeStruct: {
- auto BCCTy = dyn_cast<StructType>(transType(BCC->getType()));
- auto Members = BCCTy->getNumElements();
- auto Constants = CV.size();
- //if we try to initialize constant TypeStruct, add bitcasts
- //if src and dst types are both pointers but to different types
- if (Members == Constants) {
- for (unsigned i = 0; i < Members; ++i) {
- if (CV[i]->getType() == BCCTy->getElementType(i))
- continue;
- if (!CV[i]->getType()->isPointerTy() ||
- !BCCTy->getElementType(i)->isPointerTy())
- continue;
-
- CV[i] = ConstantExpr::getBitCast(CV[i], BCCTy->getElementType(i));
- }
- }
-
- return mapValue(BV, ConstantStruct::get(
- dyn_cast<StructType>(transType(BCC->getType())), CV));
- }
- default:
- llvm_unreachable("not implemented");
- return nullptr;
- }
- }
-
- case OpConstantSampler: {
- auto BCS = static_cast<SPIRVConstantSampler*>(BV);
- return mapValue(BV, oclTransConstantSampler(BCS));
- }
-
- case OpConstantPipeStorage: {
- auto BCPS = static_cast<SPIRVConstantPipeStorage*>(BV);
- return mapValue(BV, oclTransConstantPipeStorage(BCPS));
- }
-
- case OpSpecConstantOp: {
- auto BI = createInstFromSpecConstantOp(
- static_cast<SPIRVSpecConstantOp*>(BV));
- return mapValue(BV, transValue(BI, nullptr, nullptr, false));
- }
-
- case OpUndef:
- return mapValue(BV, UndefValue::get(transType(BV->getType())));
-
- case OpVariable: {
- auto BVar = static_cast<SPIRVVariable *>(BV);
- auto Ty = transType(BVar->getType()->getPointerElementType());
- bool IsConst = BVar->isConstant();
- llvm::GlobalValue::LinkageTypes LinkageTy = transLinkageType(BVar);
- Constant *Initializer = nullptr;
- SPIRVValue *Init = BVar->getInitializer();
- if (Init)
- Initializer = dyn_cast<Constant>(transValue(Init, F, BB, false));
- else if (LinkageTy == GlobalValue::CommonLinkage)
- // In LLVM variables with common linkage type must be initilized by 0
- Initializer = Constant::getNullValue(Ty);
- else if (BVar->getStorageClass() == SPIRVStorageClassKind::StorageClassWorkgroup)
- Initializer = dyn_cast<Constant>(UndefValue::get(Ty));
-
- SPIRVStorageClassKind BS = BVar->getStorageClass();
- if (BS == StorageClassFunction && !Init) {
- assert (BB && "Invalid BB");
- return mapValue(BV, new AllocaInst(Ty, 0, BV->getName(), BB));
- }
- auto AddrSpace = SPIRSPIRVAddrSpaceMap::rmap(BS);
- auto LVar = new GlobalVariable(*M, Ty, IsConst, LinkageTy, Initializer,
- BV->getName(), 0, GlobalVariable::NotThreadLocal, AddrSpace);
- LVar->setUnnamedAddr((IsConst && Ty->isArrayTy() &&
- Ty->getArrayElementType()->isIntegerTy(8))
- ? GlobalValue::UnnamedAddr::Global
- : GlobalValue::UnnamedAddr::None);
- SPIRVBuiltinVariableKind BVKind;
- if (BVar->isBuiltin(&BVKind))
- BuiltinGVMap[LVar] = BVKind;
- return mapValue(BV, LVar);
- }
-
- case OpFunctionParameter: {
- auto BA = static_cast<SPIRVFunctionParameter*>(BV);
- assert (F && "Invalid function");
- unsigned ArgNo = 0;
- for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E;
- ++I, ++ArgNo) {
- if (ArgNo == BA->getArgNo())
- return mapValue(BV, &(*I));
- }
- llvm_unreachable("Invalid argument");
- return nullptr;
- }
-
- case OpFunction:
- return mapValue(BV, transFunction(static_cast<SPIRVFunction *>(BV)));
-
- case OpLabel:
- return mapValue(BV, BasicBlock::Create(*Context, BV->getName(), F));
-
- default:
- // do nothing
- break;
- }
-
- // During translation of OpSpecConstantOp we create an instruction
- // corresponding to the Opcode operand and then translate this instruction.
- // For such instruction BB and F should be nullptr, because it is a constant
- // expression declared out of scope of any basic block or function.
- // All other values require valid BB pointer.
- assert(((isSpecConstantOpAllowedOp(OC) && !F && !BB) || BB) && "Invalid BB");
-
- // Creation of place holder
- if (CreatePlaceHolder) {
- auto GV = new GlobalVariable(*M,
- transType(BV->getType()),
- false,
- GlobalValue::PrivateLinkage,
- nullptr,
- std::string(kPlaceholderPrefix) + BV->getName(),
- 0, GlobalVariable::NotThreadLocal, 0);
- auto LD = new LoadInst(GV, BV->getName(), BB);
- PlaceholderMap[BV] = LD;
- return mapValue(BV, LD);
- }
-
- // Translation of instructions
- switch (BV->getOpCode()) {
- case OpBranch: {
- auto BR = static_cast<SPIRVBranch *>(BV);
- auto BI = BranchInst::Create(
- dyn_cast<BasicBlock>(transValue(BR->getTargetLabel(), F, BB)), BB);
- if (auto LM = static_cast<SPIRVLoopMerge *>(BR->getPrevious()))
- setLLVMLoopMetadata(LM, BI);
- return mapValue(BV, BI);
- }
-
- case OpBranchConditional: {
- auto BR = static_cast<SPIRVBranchConditional *>(BV);
- auto BC = BranchInst::Create(
- dyn_cast<BasicBlock>(transValue(BR->getTrueLabel(), F, BB)),
- dyn_cast<BasicBlock>(transValue(BR->getFalseLabel(), F, BB)),
- transValue(BR->getCondition(), F, BB), BB);
- if (auto LM = static_cast<SPIRVLoopMerge *>(BR->getPrevious()))
- setLLVMLoopMetadata(LM, BC);
- return mapValue(BV, BC);
- }
-
- case OpPhi: {
- auto Phi = static_cast<SPIRVPhi *>(BV);
- auto LPhi = dyn_cast<PHINode>(mapValue(
- BV, PHINode::Create(transType(Phi->getType()),
- Phi->getPairs().size() / 2, Phi->getName(), BB)));
- Phi->foreachPair([&](SPIRVValue *IncomingV, SPIRVBasicBlock *IncomingBB,
- size_t Index) {
- auto Translated = transValue(IncomingV, F, BB);
- LPhi->addIncoming(Translated,
- dyn_cast<BasicBlock>(transValue(IncomingBB, F, BB)));
- });
- return LPhi;
- }
-
- case OpUnreachable:
- return mapValue(BV, new UnreachableInst(*Context, BB));
-
- case OpReturn:
- return mapValue(BV, ReturnInst::Create(*Context, BB));
-
- case OpReturnValue: {
- auto RV = static_cast<SPIRVReturnValue *>(BV);
- return mapValue(
- BV, ReturnInst::Create(*Context,
- transValue(RV->getReturnValue(), F, BB), BB));
- }
-
- case OpLifetimeStart: {
- SPIRVLifetimeStart *LTStart = static_cast<SPIRVLifetimeStart*>(BV);
- IRBuilder<> Builder(BB);
- SPIRVWord Size = LTStart->getSize();
- ConstantInt *S = nullptr;
- if (Size)
- S = Builder.getInt64(Size);
- Value* Var = transValue(LTStart->getObject(), F, BB);
- CallInst *Start = Builder.CreateLifetimeStart(Var, S);
- return mapValue(BV, Start->getOperand(1));
- }
-
- case OpLifetimeStop: {
- SPIRVLifetimeStop *LTStop = static_cast<SPIRVLifetimeStop*>(BV);
- IRBuilder<> Builder(BB);
- SPIRVWord Size = LTStop->getSize();
- ConstantInt *S = nullptr;
- if (Size)
- S = Builder.getInt64(Size);
- auto Var = transValue(LTStop->getObject(), F, BB);
- for (const auto &I : Var->users())
- if (auto II = getLifetimeStartIntrinsic(dyn_cast<Instruction>(I)))
- return mapValue(BV, Builder.CreateLifetimeEnd(II->getOperand(1), S));
- return mapValue(BV, Builder.CreateLifetimeEnd(Var, S));
- }
-
- case OpStore: {
- SPIRVStore *BS = static_cast<SPIRVStore*>(BV);
- StoreInst *SI = new StoreInst(transValue(BS->getSrc(), F, BB),
- transValue(BS->getDst(), F, BB),
- BS->SPIRVMemoryAccess::isVolatile(),
- BS->SPIRVMemoryAccess::getAlignment(), BB);
- if (BS->SPIRVMemoryAccess::isNonTemporal())
- transNonTemporalMetadata(SI);
- return mapValue(BV, SI);
- }
-
- case OpLoad: {
- SPIRVLoad *BL = static_cast<SPIRVLoad*>(BV);
- LoadInst *LI = new LoadInst(transValue(BL->getSrc(), F, BB), BV->getName(),
- BL->SPIRVMemoryAccess::isVolatile(),
- BL->SPIRVMemoryAccess::getAlignment(), BB);
- if (BL->SPIRVMemoryAccess::isNonTemporal())
- transNonTemporalMetadata(LI);
- return mapValue(BV, LI);
- }
-
- case OpCopyMemorySized: {
- SPIRVCopyMemorySized *BC = static_cast<SPIRVCopyMemorySized *>(BV);
- CallInst *CI = nullptr;
- llvm::Value *Dst = transValue(BC->getTarget(), F, BB);
- unsigned Align = BC->getAlignment();
- llvm::Value *Size = transValue(BC->getSize(), F, BB);
- bool isVolatile = BC->SPIRVMemoryAccess::isVolatile();
- IRBuilder<> Builder(BB);
-
- // If we copy from zero-initialized array, we can optimize it to llvm.memset
- if (BC->getSource()->getOpCode() == OpBitcast) {
- SPIRVValue *Source =
- static_cast<SPIRVBitcast*>(BC->getSource())->getOperand(0);
- if (Source->isVariable()) {
- auto *Init = static_cast<SPIRVVariable*>(Source)->getInitializer();
- if (isa<OpConstantNull>(Init)) {
- SPIRVType *Ty = static_cast<SPIRVConstantNull*>(Init)->getType();
- if (isa<OpTypeArray>(Ty)) {
- SPIRVTypeArray *AT = static_cast<SPIRVTypeArray*>(Ty);
- Type *SrcTy = transType(AT->getArrayElementType());
- assert(SrcTy->isIntegerTy(8));
- llvm::Value *Src = ConstantInt::get(SrcTy, 0);
- CI = Builder.CreateMemSet(Dst, Src, Size, Align, isVolatile);
- }
- }
- }
- }
- if (!CI) {
- llvm::Value *Src = transValue(BC->getSource(), F, BB);
- CI = Builder.CreateMemCpy(Dst, Align, Src, Align, Size, isVolatile);
- }
- if (isFuncNoUnwind())
- CI->getFunction()->addFnAttr(Attribute::NoUnwind);
- return mapValue(BV, CI);
- }
-
- case OpSelect: {
- SPIRVSelect *BS = static_cast<SPIRVSelect*>(BV);
- return mapValue(BV,
- SelectInst::Create(transValue(BS->getCondition(), F, BB),
- transValue(BS->getTrueValue(), F, BB),
- transValue(BS->getFalseValue(), F, BB),
- BV->getName(), BB));
- }
-
- case OpLine:
- case OpSelectionMerge: // OpenCL Compiler does not use this instruction
- case OpLoopMerge: // Should be translated at OpBranch or OpBranchConditional cases
- return nullptr;
-
- case OpSwitch: {
- auto BS = static_cast<SPIRVSwitch *>(BV);
- auto Select = transValue(BS->getSelect(), F, BB);
- auto LS = SwitchInst::Create(
- Select, dyn_cast<BasicBlock>(transValue(BS->getDefault(), F, BB)),
- BS->getNumPairs(), BB);
- BS->foreachPair(
- [&](SPIRVSwitch::LiteralTy Literals, SPIRVBasicBlock *Label) {
- assert(!Literals.empty() && "Literals should not be empty");
- assert(Literals.size() <= 2 && "Number of literals should not be more then two");
- uint64_t Literal = uint64_t(Literals.at(0));
- if (Literals.size() == 2) {
- Literal += uint64_t(Literals.at(1)) << 32;
- }
- LS->addCase(ConstantInt::get(dyn_cast<IntegerType>(Select->getType()), Literal),
- dyn_cast<BasicBlock>(transValue(Label, F, BB)));
- });
- return mapValue(BV, LS);
- }
-
- case OpVectorTimesScalar: {
- auto VTS = static_cast<SPIRVVectorTimesScalar*>(BV);
- IRBuilder<> Builder(BB);
- auto Scalar = transValue(VTS->getScalar(), F, BB);
- auto Vector = transValue(VTS->getVector(), F, BB);
- assert(Vector->getType()->isVectorTy() && "Invalid type");
- unsigned vecSize = Vector->getType()->getVectorNumElements();
- auto NewVec = Builder.CreateVectorSplat(vecSize, Scalar, Scalar->getName());
- NewVec->takeName(Scalar);
- auto Scale = Builder.CreateFMul(Vector, NewVec, "scale");
- return mapValue(BV, Scale);
- }
-
- case OpCopyObject: {
- SPIRVCopyObject *CO = static_cast<SPIRVCopyObject *>(BV);
- AllocaInst* AI = new AllocaInst(transType(CO->getOperand()->getType()), 0, "", BB);
- new StoreInst(transValue(CO->getOperand(), F, BB), AI, BB);
- LoadInst* LI = new LoadInst(AI, "", BB);
- return mapValue(BV, LI);
- }
-
- case OpAccessChain:
- case OpInBoundsAccessChain:
- case OpPtrAccessChain:
- case OpInBoundsPtrAccessChain: {
- auto AC = static_cast<SPIRVAccessChainBase *>(BV);
- auto Base = transValue(AC->getBase(), F, BB);
- auto Index = transValue(AC->getIndices(), F, BB);
- if (!AC->hasPtrIndex())
- Index.insert(Index.begin(), getInt32(M, 0));
- auto IsInbound = AC->isInBounds();
- Value *V = nullptr;
- if (BB) {
- auto GEP = GetElementPtrInst::Create(nullptr, Base, Index, BV->getName(), BB);
- GEP->setIsInBounds(IsInbound);
- V = GEP;
- } else {
- V = ConstantExpr::getGetElementPtr(nullptr, dyn_cast<Constant>(Base), Index,
- IsInbound);
- }
- return mapValue(BV, V);
- }
-
- case OpCompositeConstruct: {
- auto CC = static_cast<SPIRVCompositeConstruct *>(BV);
- auto Constituents = transValue(CC->getConstituents(), F, BB);
- std::vector<Constant*> CV;
- for (const auto &I : Constituents) {
- CV.push_back(dyn_cast<Constant>(I));
- }
- switch (BV->getType()->getOpCode()) {
- case OpTypeVector:
- return mapValue(BV, ConstantVector::get(CV));
- case OpTypeArray:
- return mapValue(BV, ConstantArray::get(
- dyn_cast<ArrayType>(transType(CC->getType())), CV));
- case OpTypeStruct:
- return mapValue(BV, ConstantStruct::get(
- dyn_cast<StructType>(transType(CC->getType())), CV));
- default:
- llvm_unreachable("Unhandled type!");
- }
- }
-
- case OpCompositeExtract: {
- SPIRVCompositeExtract *CE = static_cast<SPIRVCompositeExtract *>(BV);
- if (CE->getComposite()->getType()->isTypeVector()) {
- assert(CE->getIndices().size() == 1 && "Invalid index");
- return mapValue(
- BV, ExtractElementInst::Create(
- transValue(CE->getComposite(), F, BB),
- ConstantInt::get(*Context, APInt(32, CE->getIndices()[0])),
- BV->getName(), BB));
- }
- return mapValue(
- BV, ExtractValueInst::Create(
- transValue(CE->getComposite(), F, BB),
- CE->getIndices(), BV->getName(), BB));
- }
-
- case OpVectorExtractDynamic: {
- auto CE = static_cast<SPIRVVectorExtractDynamic *>(BV);
- return mapValue(
- BV, ExtractElementInst::Create(transValue(CE->getVector(), F, BB),
- transValue(CE->getIndex(), F, BB),
- BV->getName(), BB));
- }
-
- case OpCompositeInsert: {
- auto CI = static_cast<SPIRVCompositeInsert *>(BV);
- if (CI->getComposite()->getType()->isTypeVector()) {
- assert(CI->getIndices().size() == 1 && "Invalid index");
- return mapValue(
- BV, InsertElementInst::Create(
- transValue(CI->getComposite(), F, BB),
- transValue(CI->getObject(), F, BB),
- ConstantInt::get(*Context, APInt(32, CI->getIndices()[0])),
- BV->getName(), BB));
- }
- return mapValue(
- BV, InsertValueInst::Create(
- transValue(CI->getComposite(), F, BB),
- transValue(CI->getObject(), F, BB),
- CI->getIndices(), BV->getName(), BB));
- }
-
- case OpVectorInsertDynamic: {
- auto CI = static_cast<SPIRVVectorInsertDynamic *>(BV);
- return mapValue(
- BV, InsertElementInst::Create(transValue(CI->getVector(), F, BB),
- transValue(CI->getComponent(), F, BB),
- transValue(CI->getIndex(), F, BB),
- BV->getName(), BB));
- }
-
- case OpVectorShuffle: {
- auto VS = static_cast<SPIRVVectorShuffle *>(BV);
- std::vector<Constant *> Components;
- IntegerType *Int32Ty = IntegerType::get(*Context, 32);
- for (auto I : VS->getComponents()) {
- if (I == static_cast<SPIRVWord>(-1))
- Components.push_back(UndefValue::get(Int32Ty));
- else
- Components.push_back(ConstantInt::get(Int32Ty, I));
- }
- return mapValue(BV,
- new ShuffleVectorInst(transValue(VS->getVector1(), F, BB),
- transValue(VS->getVector2(), F, BB),
- ConstantVector::get(Components),
- BV->getName(), BB));
- }
-
- case OpFunctionCall: {
- SPIRVFunctionCall *BC = static_cast<SPIRVFunctionCall *>(BV);
- auto Call = CallInst::Create(transFunction(BC->getFunction()),
- transValue(BC->getArgumentValues(), F, BB),
- BC->getName(), BB);
- setCallingConv(Call);
- setAttrByCalledFunc(Call);
- return mapValue(BV, Call);
- }
-
- case OpExtInst:
- return mapValue(
- BV, transOCLBuiltinFromExtInst(static_cast<SPIRVExtInst *>(BV), BB));
-
- case OpControlBarrier:
- case OpMemoryBarrier:
- return mapValue(
- BV, transOCLBarrierFence(static_cast<SPIRVInstruction *>(BV), BB));
-
- case OpSNegate: {
- SPIRVUnary *BC = static_cast<SPIRVUnary *>(BV);
- return mapValue(
- BV, BinaryOperator::CreateNSWNeg(transValue(BC->getOperand(0), F, BB),
- BV->getName(), BB));
- }
-
- case OpFMod: {
- // translate OpFMod(a, b) to copysign(frem(a, b), b)
- SPIRVFMod *FMod = static_cast<SPIRVFMod *>(BV);
- auto Dividend = transValue(FMod->getDividend(), F, BB);
- auto Divisor = transValue(FMod->getDivisor(), F, BB);
- auto FRem = BinaryOperator::CreateFRem(Dividend, Divisor, "frem.res", BB);
-
- std::string UnmangledName = OCLExtOpMap::map(OpenCLLIB::Copysign);
- std::string MangledName = "copysign";
-
- std::vector<Type *> ArgTypes;
- ArgTypes.push_back(FRem->getType());
- ArgTypes.push_back(Divisor->getType());
- MangleOpenCLBuiltin(UnmangledName, ArgTypes, MangledName);
-
- auto FT = FunctionType::get(transType(BV->getType()), ArgTypes, false);
- auto Func = Function::Create(FT, GlobalValue::ExternalLinkage, MangledName, M);
- Func->setCallingConv(CallingConv::SPIR_FUNC);
- if (isFuncNoUnwind())
- Func->addFnAttr(Attribute::NoUnwind);
-
- std::vector<Value *> Args;
- Args.push_back(FRem);
- Args.push_back(Divisor);
-
- auto Call = CallInst::Create(Func, Args, "copysign", BB);
- setCallingConv(Call);
- addFnAttr(Context, Call, Attribute::NoUnwind);
- return mapValue(BV, Call);
- }
- case OpFNegate: {
- SPIRVUnary *BC = static_cast<SPIRVUnary *>(BV);
- return mapValue(
- BV, BinaryOperator::CreateFNeg(transValue(BC->getOperand(0), F, BB),
- BV->getName(), BB));
- }
-
- case OpNot: {
- SPIRVUnary *BC = static_cast<SPIRVUnary *>(BV);
- return mapValue(
- BV, BinaryOperator::CreateNot(transValue(BC->getOperand(0), F, BB),
- BV->getName(), BB));
- }
-
- case OpAll :
- case OpAny :
- return mapValue(BV,
- transOCLAllAny(static_cast<SPIRVInstruction *>(BV), BB));
-
- case OpIsFinite :
- case OpIsInf :
- case OpIsNan :
- case OpIsNormal :
- case OpSignBitSet :
- return mapValue(BV,
- transOCLRelational(static_cast<SPIRVInstruction *>(BV), BB));
- case OpEnqueueKernel :
- return mapValue(BV, transEnqueueKernelBI(
- static_cast<SPIRVInstruction *>(BV), BB));
- case OpGetKernelWorkGroupSize :
- case OpGetKernelPreferredWorkGroupSizeMultiple :
- return mapValue(BV, transWGSizeBI(
- static_cast<SPIRVInstruction *>(BV), BB));
- default: {
- auto OC = BV->getOpCode();
- if (isSPIRVCmpInstTransToLLVMInst(static_cast<SPIRVInstruction*>(BV))) {
- return mapValue(BV, transCmpInst(BV, BB, F));
- } else if ((OCLSPIRVBuiltinMap::rfind(OC, nullptr) ||
- isIntelSubgroupOpCode(OC)) &&
- !isAtomicOpCode(OC) &&
- !isGroupOpCode(OC) &&
- !isPipeOpCode(OC)) {
- return mapValue(BV, transOCLBuiltinFromInst(
- static_cast<SPIRVInstruction *>(BV), BB));
- } else if (isBinaryShiftLogicalBitwiseOpCode(OC) ||
- isLogicalOpCode(OC)) {
- return mapValue(BV, transShiftLogicalBitwiseInst(BV, BB, F));
- } else if (isCvtOpCode(OC)) {
- auto BI = static_cast<SPIRVInstruction *>(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, transSPIRVBuiltinFromInst(
- static_cast<SPIRVInstruction *>(BV), BB));
- }
-
- SPIRVDBG(spvdbgs() << "Cannot translate " << *BV << '\n';)
- llvm_unreachable("Translation of SPIRV instruction not implemented");
- return NULL;
- }
-}
-
-template<class SourceTy, class FuncTy>
-bool
-SPIRVToLLVM::foreachFuncCtlMask(SourceTy Source, FuncTy Func) {
- SPIRVWord FCM = Source->getFuncCtlMask();
- SPIRSPIRVFuncCtlMaskMap::foreach([&](Attribute::AttrKind Attr,
- SPIRVFunctionControlMaskKind Mask){
- if (FCM & Mask)
- Func(Attr);
- });
- return true;
-}
-
-Function *
-SPIRVToLLVM::transFunction(SPIRVFunction *BF) {
- auto Loc = FuncMap.find(BF);
- if (Loc != FuncMap.end())
- return Loc->second;
-
- auto IsKernel = BM->isEntryPoint(ExecutionModelKernel, BF->getId());
- auto Linkage = IsKernel ? GlobalValue::ExternalLinkage : transLinkageType(BF);
- FunctionType *FT = dyn_cast<FunctionType>(transType(BF->getFunctionType()));
- Function *F = dyn_cast<Function>(mapValue(BF, Function::Create(FT, Linkage,
- BF->getName(), M)));
- assert(F);
- mapFunction(BF, F);
- if (!F->isIntrinsic()) {
- F->setCallingConv(IsKernel ? CallingConv::SPIR_KERNEL :
- CallingConv::SPIR_FUNC);
- if (isFuncNoUnwind())
- F->addFnAttr(Attribute::NoUnwind);
- foreachFuncCtlMask(BF, [&](Attribute::AttrKind Attr){
- F->addFnAttr(Attr);
- });
- }
-
- for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E;
- ++I) {
- auto BA = BF->getArgument(I->getArgNo());
- mapValue(BA, &(*I));
- setName(&(*I), BA);
- BA->foreachAttr([&](SPIRVFuncParamAttrKind Kind){
- if (Kind == FunctionParameterAttributeNoWrite)
- return;
- F->addAttribute(I->getArgNo() + 1, SPIRSPIRVFuncParamAttrMap::rmap(Kind));
- });
-
- SPIRVWord MaxOffset = 0;
- if (BA->hasDecorate(DecorationMaxByteOffset, 0, &MaxOffset)) {
- AttrBuilder Builder;
- Builder.addDereferenceableAttr(MaxOffset);
- I->addAttrs(Builder);
- }
- }
- BF->foreachReturnValueAttr([&](SPIRVFuncParamAttrKind Kind){
- if (Kind == FunctionParameterAttributeNoWrite)
- return;
- F->addAttribute(AttributeList::ReturnIndex,
- SPIRSPIRVFuncParamAttrMap::rmap(Kind));
- });
-
- // Creating all basic blocks before creating instructions.
- for (size_t I = 0, E = BF->getNumBasicBlock(); I != E; ++I) {
- transValue(BF->getBasicBlock(I), F, nullptr);
- }
-
- for (size_t I = 0, E = BF->getNumBasicBlock(); I != E; ++I) {
- SPIRVBasicBlock *BBB = BF->getBasicBlock(I);
- BasicBlock *BB = dyn_cast<BasicBlock>(transValue(BBB, F, nullptr));
- for (size_t BI = 0, BE = BBB->getNumInst(); BI != BE; ++BI) {
- SPIRVInstruction *BInst = BBB->getInst(BI);
- transValue(BInst, F, BB, false);
- }
- }
- return F;
-}
-
-/// LLVM convert builtin functions is translated to two instructions:
-/// y = i32 islessgreater(float x, float z) ->
-/// y = i32 ZExt(bool LessGreater(float x, float z))
-/// When translating back, for simplicity, a trunc instruction is inserted
-/// w = bool LessGreater(float x, float z) ->
-/// w = bool Trunc(i32 islessgreater(float x, float z))
-/// Optimizer should be able to remove the redundant trunc/zext
-void
-SPIRVToLLVM::transOCLBuiltinFromInstPreproc(SPIRVInstruction* BI, Type *&RetTy,
- std::vector<SPIRVValue *> &Args) {
- if (!BI->hasType())
- return;
- auto BT = BI->getType();
- auto OC = BI->getOpCode();
- if (isCmpOpCode(BI->getOpCode())) {
- if (BT->isTypeBool())
- RetTy = IntegerType::getInt32Ty(*Context);
- else if (BT->isTypeVectorBool())
- RetTy = VectorType::get(IntegerType::get(*Context,
- Args[0]->getType()->getVectorComponentType()->isTypeFloat(64)?64:32),
- BT->getVectorComponentCount());
- else
- llvm_unreachable("invalid compare instruction");
- } else if (OC == OpGenericCastToPtrExplicit)
- Args.pop_back();
- else if (OC == OpImageRead && Args.size() > 2) {
- // Drop "Image operands" argument
- Args.erase(Args.begin() + 2);
- }
-}
-
-Instruction*
-SPIRVToLLVM::transOCLBuiltinPostproc(SPIRVInstruction* BI,
- CallInst* CI, BasicBlock* BB, const std::string &DemangledName) {
- auto OC = BI->getOpCode();
- if (isCmpOpCode(OC) &&
- BI->getType()->isTypeVectorOrScalarBool()) {
- return CastInst::Create(Instruction::Trunc, CI, transType(BI->getType()),
- "cvt", BB);
- }
- if (OC == OpImageSampleExplicitLod)
- return postProcessOCLReadImage(BI, CI, DemangledName);
- if (OC == OpImageWrite) {
- return postProcessOCLWriteImage(BI, CI, DemangledName);
- }
- if (OC == OpGenericPtrMemSemantics)
- return BinaryOperator::CreateShl(CI, getInt32(M, 8), "", BB);
- if (OC == OpImageQueryFormat)
- return BinaryOperator::CreateSub(
- CI, getInt32(M, OCLImageChannelDataTypeOffset), "", BB);
- if (OC == OpImageQueryOrder)
- return BinaryOperator::CreateSub(
- CI, getInt32(M, OCLImageChannelOrderOffset), "", BB);
- if (OC == OpBuildNDRange)
- return postProcessOCLBuildNDRange(BI, CI, DemangledName);
- if (OC == OpGroupAll || OC == OpGroupAny)
- return postProcessGroupAllAny(CI, DemangledName);
- if (SPIRVEnableStepExpansion &&
- (DemangledName == "smoothstep" ||
- DemangledName == "step"))
- return expandOCLBuiltinWithScalarArg(CI, DemangledName);
- return CI;
-}
-
-static void adaptBlockInvoke(Function *Invoke, Type *BlockStructTy) {
- // As first argument block invoke takes a pointer to captured data.
- // We pass to block invoke whole block structure, not only captured data
- // as it expected. So we need to update original function to unpack expected
- // captured data and use it instead of an original argument
- //
- // %block = bitcast i8 addrspace(4)* to <{ ..., [X x i8] }> addrspace(4)*
- // %block.1 = addrspacecast %block to <{ ..., [X x i8] }>*
- // %captured = getelementptr <{ ..., [X x i8] }>, i32 0, i32 5
- // %captured.1 = bitcast %captured to i8*
-
- BasicBlock *BB = &(Invoke->getEntryBlock());
- BB->splitBasicBlock(BB->begin(), "invoke");
- auto FirstArg = &*(Invoke->arg_begin());
- IRBuilder<> Builder(BB, BB->begin());
-
- auto FirstArgTy = dyn_cast<PointerType>(FirstArg->getType());
- assert(FirstArgTy && "Expects that first argument of invoke is a pointer");
- unsigned FirstArgAS = FirstArgTy->getAddressSpace();
-
- auto Int8PtrTy =
- Type::getInt8PtrTy(Invoke->getParent()->getContext(), FirstArgAS);
- auto BlockStructPtrTy = PointerType::get(BlockStructTy, FirstArgAS);
-
- auto Int32Ty = Type::getInt32Ty(Invoke->getParent()->getContext());
- Value *CapturedGEPIndices[2] = { ConstantInt::get(Int32Ty, 0),
- ConstantInt::get(Int32Ty, 5) };
- auto BlockToStructCast =
- Builder.CreateBitCast(FirstArg, BlockStructPtrTy, "block");
- auto CapturedGEP = Builder.CreateGEP(BlockToStructCast, CapturedGEPIndices);
- auto CapturedToInt8Cast = Builder.CreateBitCast(CapturedGEP, Int8PtrTy);
-
- FirstArg->replaceUsesOutsideBlock(CapturedToInt8Cast, BB);
-}
-
-static Type *getOrCreateBlockDescTy(Module *M) {
- // Get or create block descriptor type which contains block size
- // in the last element: %struct.__block_descriptor = type { i64, i64 }
- auto BlockDescTy = M->getTypeByName("struct.__block_descriptor");
- if (BlockDescTy)
- return BlockDescTy;
-
- auto Int64Ty = Type::getInt64Ty(M->getContext());
- Type *BlockDescElements[2] = {/*Reserved*/ Int64Ty, /*Block size*/ Int64Ty };
- return StructType::create(M->getContext(), BlockDescElements,
- "struct.__block_descriptor");
-}
-
-Value *
-SPIRVToLLVM::transEnqueuedBlock(SPIRVValue *SInvoke, SPIRVValue *SCaptured,
- SPIRVValue *SCaptSize, SPIRVValue *SCaptAlignment,
- Function *LBI, BasicBlock *LBB) {
- // Search if that block have been already translated
- auto Loc = BlockMap.find(SInvoke);
- if (Loc != BlockMap.end())
- return Loc->second;
-
- IRBuilder<> Builder(LBB);
- const DataLayout &DL = M->getDataLayout();
-
- // Translate block and its arguments from SPIRV values to LLVM
- auto LInvoke = transFunction(static_cast<SPIRVFunction *>(SInvoke));
- auto LCaptured = transValue(SCaptured, LBI, LBB, false);
- auto LCaptSize =
- dyn_cast<ConstantInt>(transValue(SCaptSize, LBI, LBB, false));
- auto LCaptAlignment =
- dyn_cast<ConstantInt>(transValue(SCaptAlignment, LBI, LBB, false));
-
- // Create basic types
- auto Int8Ty = Type::getInt8Ty(*Context);
- auto Int32Ty = Type::getInt32Ty(*Context);
- auto Int8PtrTy = Type::getInt8PtrTy(*Context, SPIRAS_Private);
- auto Int8PtrTyGen = Type::getInt8PtrTy(*Context, SPIRAS_Generic);
- auto BlockDescTy = getOrCreateBlockDescTy(M);
- auto BlockDescPtrTy = BlockDescTy->getPointerTo(SPIRAS_Private);
-
- // Create a block as structure:
- // <{ i8*, i32, i32, i8*, %struct.__block_descriptor* }>
- SmallVector<Type *, 8> BlockEls =
- { /*isa*/ Int8PtrTy, /*flags*/ Int32Ty, /*reserved*/ Int32Ty,
- /*invoke*/ Int8PtrTy, /*block_descriptor*/ BlockDescPtrTy };
-
- // Add captured if any
- // <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, [X x i8] }>
- // Note: captured data stored in structure as array of char
- if (LCaptSize->getZExtValue() > 0)
- BlockEls.push_back(ArrayType::get(Int8Ty, LCaptSize->getZExtValue()));
-
- auto BlockTy = StructType::get(*Context, BlockEls, /*isPacked*/ true);
-
- // Allocate block on the stack, then store data to it
- auto BlockAlloca = Builder.CreateAlloca(BlockTy, nullptr, "block");
- BlockAlloca->setAlignment(DL.getPrefTypeAlignment(BlockTy));
-
- auto getIndices = [Int32Ty](int a, int b) -> SmallVector<Value *, 2> {
- return { ConstantInt::get(Int32Ty, a), ConstantInt::get(Int32Ty, b) };
- };
-
- // 1. isa, flags and reserved fields isn't used in current implementation
- // Fill them the same way as clang does
- auto IsaGEP = Builder.CreateGEP(BlockAlloca, getIndices(0, 0));
- Builder.CreateStore(ConstantPointerNull::get(Int8PtrTy), IsaGEP);
- auto FlagsGEP = Builder.CreateGEP(BlockAlloca, getIndices(0, 1));
- Builder.CreateStore(ConstantInt::get(Int32Ty, 1342177280), FlagsGEP);
- auto ReservedGEP = Builder.CreateGEP(BlockAlloca, getIndices(0, 2));
- Builder.CreateStore(ConstantInt::get(Int32Ty, 0), ReservedGEP);
-
- // 2. Store pointer to block invoke to the structure
- auto InvokeCast = Builder.CreateBitCast(LInvoke, Int8PtrTy, "invoke");
- auto InvokeGEP = Builder.CreateGEP(BlockAlloca, getIndices(0, 3));
- Builder.CreateStore(InvokeCast, InvokeGEP);
-
- // 3. Create and store a pointer to the block descriptor global value
- uint64_t SizeOfBlock = DL.getTypeAllocSize(BlockTy);
-
- auto Int64Ty = Type::getInt64Ty(*Context);
- Constant *BlockDescEls[2] = { ConstantInt::get(Int64Ty, 0),
- ConstantInt::get(Int64Ty, SizeOfBlock) };
- auto BlockDesc =
- ConstantStruct::get(dyn_cast<StructType>(BlockDescTy), BlockDescEls);
-
- auto BlockDescGV =
- new GlobalVariable(*M, BlockDescTy, true, GlobalValue::InternalLinkage,
- BlockDesc, "__block_descriptor_spirv");
- auto BlockDescGEP =
- Builder.CreateGEP(BlockAlloca, getIndices(0, 4), "block.descriptor");
- Builder.CreateStore(BlockDescGV, BlockDescGEP);
-
- // 4. Copy captured data to the structure
- if (LCaptSize->getZExtValue() > 0) {
- auto CapturedGEP =
- Builder.CreateGEP(BlockAlloca, getIndices(0, 5), "block.captured");
- auto CapturedGEPCast = Builder.CreateBitCast(CapturedGEP, Int8PtrTy);
-
- // We can't make any guesses about type of captured data, so
- // let's copy it through memcpy
- Builder.CreateMemCpy(CapturedGEPCast, LCaptAlignment->getZExtValue(),
- LCaptured, LCaptAlignment->getZExtValue(), LCaptSize,
- SCaptured->isVolatile());
-
- // Fix invoke function to correctly process its first argument
- adaptBlockInvoke(LInvoke, BlockTy);
- }
- auto BlockCast = Builder.CreateBitCast(BlockAlloca, Int8PtrTy);
- auto BlockCastGen = Builder.CreateAddrSpaceCast(BlockCast, Int8PtrTyGen);
- BlockMap[SInvoke] = BlockCastGen;
- return BlockCastGen;
-}
-
-Instruction *
-SPIRVToLLVM::transEnqueueKernelBI(SPIRVInstruction *BI, BasicBlock *BB) {
- Type *IntTy = Type::getInt32Ty(*Context);
-
- // Find or create enqueue kernel BI declaration
- auto Ops = BI->getOperands();
- bool hasVaargs = Ops.size() > 10;
-
- std::string FName = hasVaargs ? "__enqueue_kernel_events_vaargs"
- : "__enqueue_kernel_basic_events";
- Function* F = M->getFunction(FName);
- if (!F) {
- Type *EventTy = PointerType::get(
- getOrCreateOpaquePtrType(M, SPIR_TYPE_NAME_CLK_EVENT_T, SPIRAS_Private),
- SPIRAS_Generic);
-
- SmallVector<Type *, 8> Tys = {
- transType(Ops[0]->getType()), // queue
- IntTy, // flags
- transType(Ops[2]->getType()), // ndrange
- IntTy, EventTy, EventTy, // events
- Type::getInt8PtrTy(*Context, SPIRAS_Generic) // block
- };
- if (hasVaargs)
- Tys.push_back(IntTy); // Number of variadics if any
-
- FunctionType* FT = FunctionType::get(IntTy, Tys, hasVaargs);
- F = Function::Create(FT, GlobalValue::ExternalLinkage, FName, M);
- if (isFuncNoUnwind())
- F->addFnAttr(Attribute::NoUnwind);
- }
-
- // Create call to enqueue kernel BI
- SmallVector<Value *, 8> Args = {
- transValue(Ops[0], F, BB, false), // queue
- transValue(Ops[1], F, BB, false), // flags
- transValue(Ops[2], F, BB, false), // ndrange
- transValue(Ops[3], F, BB, false), // events number
- transDeviceEvent(Ops[4], F, BB), // event_wait_list
- transDeviceEvent(Ops[5], F, BB), // event_ret
- transEnqueuedBlock(Ops[6], Ops[7], Ops[8], Ops[9], F, BB) // block
- };
-
- if (hasVaargs) {
- Args.push_back(ConstantInt::get(IntTy, Ops.size() - 10)); // Number of vaargs
- for (unsigned i = 10; i < Ops.size(); ++i)
- Args.push_back(transValue(Ops[i], F, BB, false));
- }
- auto Call = CallInst::Create(F, Args, "", BB);
- setName(Call, BI);
- setAttrByCalledFunc(Call);
- return Call;
-}
-
-Instruction *
-SPIRVToLLVM::transWGSizeBI(SPIRVInstruction *BI, BasicBlock *BB) {
- std::string FName =
- (BI->getOpCode() == OpGetKernelWorkGroupSize)
- ? "__get_kernel_work_group_size_impl"
- : "__get_kernel_preferred_work_group_multiple_impl";
-
- Function* F = M->getFunction(FName);
- if (!F) {
- auto Int8PtrTyGen = Type::getInt8PtrTy(*Context, SPIRAS_Generic);
- FunctionType* FT =
- FunctionType::get(Type::getInt32Ty(*Context), Int8PtrTyGen, false);
- F = Function::Create(FT, GlobalValue::ExternalLinkage, FName, M);
- if (isFuncNoUnwind())
- F->addFnAttr(Attribute::NoUnwind);
- }
- auto Ops = BI->getOperands();
- auto Block = transEnqueuedBlock(Ops[0], Ops[1], Ops[2], Ops[3], F, BB);
- auto Call = CallInst::Create(F, Block, "", BB);
- setName(Call, BI);
- setAttrByCalledFunc(Call);
- return Call;
-}
-
-Instruction *
-SPIRVToLLVM::transBuiltinFromInst(const std::string& FuncName,
- SPIRVInstruction* BI, BasicBlock* BB) {
- std::string MangledName;
- auto Ops = BI->getOperands();
- Type* RetTy = BI->hasType() ? transType(BI->getType()) :
- Type::getVoidTy(*Context);
- transOCLBuiltinFromInstPreproc(BI, RetTy, Ops);
- std::vector<Type*> ArgTys = transTypeVector(
- SPIRVInstruction::getOperandTypes(Ops));
- bool HasFuncPtrArg = false;
- for (auto& I:ArgTys) {
- if (isa<FunctionType>(I)) {
- I = PointerType::get(I, SPIRAS_Private);
- HasFuncPtrArg = true;
- }
- }
- if (!HasFuncPtrArg)
- MangleOpenCLBuiltin(FuncName, ArgTys, MangledName);
- else
- MangledName = decorateSPIRVFunction(FuncName);
- Function* Func = M->getFunction(MangledName);
- FunctionType* FT = FunctionType::get(RetTy, ArgTys, false);
- // ToDo: Some intermediate functions have duplicate names with
- // different function types. This is OK if the function name
- // is used internally and finally translated to unique function
- // names. However it is better to have a way to differentiate
- // between intermidiate functions and final functions and make
- // sure final functions have unique names.
- SPIRVDBG(
- if (!HasFuncPtrArg && Func && Func->getFunctionType() != FT) {
- dbgs() << "Warning: Function name conflict:\n"
- << *Func << '\n'
- << " => " << *FT << '\n';
- }
- )
- if (!Func || Func->getFunctionType() != FT) {
- DEBUG(for (auto& I:ArgTys) {
- dbgs() << *I << '\n';
- });
- Func = Function::Create(FT, GlobalValue::ExternalLinkage, MangledName, M);
- Func->setCallingConv(CallingConv::SPIR_FUNC);
- if (isFuncNoUnwind())
- Func->addFnAttr(Attribute::NoUnwind);
- }
- auto Call = CallInst::Create(Func,
- transValue(Ops, BB->getParent(), BB), "", BB);
- setName(Call, BI);
- setAttrByCalledFunc(Call);
- SPIRVDBG(spvdbgs() << "[transInstToBuiltinCall] " << *BI << " -> "; dbgs() <<
- *Call << '\n';)
- Instruction *Inst = Call;
- Inst = transOCLBuiltinPostproc(BI, Call, BB, FuncName);
- return Inst;
-}
-
-std::string
-SPIRVToLLVM::getOCLBuiltinName(SPIRVInstruction* BI) {
- auto OC = BI->getOpCode();
- if (OC == OpGenericCastToPtrExplicit)
- return getOCLGenericCastToPtrName(BI);
- if (isCvtOpCode(OC))
- return getOCLConvertBuiltinName(BI);
- if (OC == OpBuildNDRange) {
- auto NDRangeInst = static_cast<SPIRVBuildNDRange *>(BI);
- auto EleTy = ((NDRangeInst->getOperands())[0])->getType();
- int Dim = EleTy->isTypeArray() ? EleTy->getArrayLength() : 1;
- // cygwin does not have std::to_string
- ostringstream OS;
- OS << Dim;
- assert((EleTy->isTypeInt() && Dim == 1) ||
- (EleTy->isTypeArray() && Dim >= 2 && Dim <= 3));
- return std::string(kOCLBuiltinName::NDRangePrefix) + OS.str() + "D";
- }
- if (isIntelSubgroupOpCode(OC)) {
- std::stringstream Name;
- SPIRVType *DataTy = nullptr;
- switch (OC) {
- case OpSubgroupBlockReadINTEL:
- case OpSubgroupImageBlockReadINTEL:
- Name << "intel_sub_group_block_read";
- DataTy = BI->getType();
- break;
- case OpSubgroupBlockWriteINTEL:
- Name << "intel_sub_group_block_write";
- DataTy = BI->getOperands()[1]->getType();
- break;
- case OpSubgroupImageBlockWriteINTEL:
- Name << "intel_sub_group_block_write";
- DataTy = BI->getOperands()[2]->getType();
- break;
- default:
- return OCLSPIRVBuiltinMap::rmap(OC);
- }
- if (DataTy) {
- if (DataTy->getBitWidth() == 16)
- Name << "_us";
- if (DataTy->isTypeVector()) {
- if (unsigned ComponentCount = DataTy->getVectorComponentCount())
- Name << ComponentCount;
- }
- }
- return Name.str();
- }
- auto Name = OCLSPIRVBuiltinMap::rmap(OC);
-
- SPIRVType *T = nullptr;
- switch(OC) {
- case OpImageRead:
- T = BI->getType();
- break;
- case OpImageWrite:
- T = BI->getOperands()[2]->getType();
- break;
- default:
- // do nothing
- break;
- }
- if (T && T->isTypeVector())
- T = T->getVectorComponentType();
- if (T)
- Name += T->isTypeFloat()?'f':'i';
-
- return Name;
-}
-
-Instruction *
-SPIRVToLLVM::transOCLBuiltinFromInst(SPIRVInstruction *BI, BasicBlock *BB) {
- assert(BB && "Invalid BB");
- auto FuncName = getOCLBuiltinName(BI);
- return transBuiltinFromInst(FuncName, BI, BB);
-}
-
-Instruction *
-SPIRVToLLVM::transSPIRVBuiltinFromInst(SPIRVInstruction *BI, BasicBlock *BB) {
- assert(BB && "Invalid BB");
- string Suffix = "";
- if (BI->getOpCode() == OpCreatePipeFromPipeStorage) {
- auto CPFPS = static_cast<SPIRVCreatePipeFromPipeStorage*>(BI);
- assert(CPFPS->getType()->isTypePipe() &&
- "Invalid type of CreatePipeFromStorage");
- auto PipeType = static_cast<SPIRVTypePipe*>(CPFPS->getType());
- switch (PipeType->getAccessQualifier()) {
+//===- SPIRVReader.cpp - Converts SPIR-V to LLVM ----------------*- C++ -*-===// +// +// The LLVM/SPIR-V 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file implements conversion of SPIR-V binary to LLVM IR. +/// +//===----------------------------------------------------------------------===// +#include "SPIRVUtil.h" +#include "SPIRVType.h" +#include "SPIRVValue.h" +#include "SPIRVModule.h" +#include "SPIRVFunction.h" +#include "SPIRVBasicBlock.h" +#include "SPIRVInstruction.h" +#include "SPIRVExtInst.h" +#include "SPIRVInternal.h" +#include "SPIRVMDBuilder.h" +#include "OCLUtil.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" + +#include <algorithm> +#include <cstdlib> +#include <functional> +#include <fstream> +#include <iostream> +#include <iterator> +#include <map> +#include <set> +#include <sstream> +#include <string> + +#define DEBUG_TYPE "spirv" + +using namespace std; +using namespace llvm; +using namespace SPIRV; +using namespace OCLUtil; + +namespace SPIRV{ + +cl::opt<bool> SPIRVEnableStepExpansion("spirv-expand-step", cl::init(true), + cl::desc("Enable expansion of OpenCL step and smoothstep function")); + +cl::opt<bool> SPIRVGenKernelArgNameMD("spirv-gen-kernel-arg-name-md", + cl::init(false), cl::desc("Enable generating OpenCL kernel argument name " + "metadata")); + +cl::opt<bool> SPIRVGenImgTypeAccQualPostfix("spirv-gen-image-type-acc-postfix", + cl::init(false), cl::desc("Enable generating access qualifier postfix" + " in OpenCL image type names")); + +// Prefix for placeholder global variable name. +const char* kPlaceholderPrefix = "placeholder."; + +// Save the translated LLVM before validation for debugging purpose. +static bool DbgSaveTmpLLVM = false; +static const char *DbgTmpLLVMFileName = "_tmp_llvmbil.ll"; + +namespace kOCLTypeQualifierName { + const static char *Const = "const"; + const static char *Volatile = "volatile"; + const static char *Restrict = "restrict"; + const static char *Pipe = "pipe"; +} + +typedef std::pair < unsigned, AttributeList > AttributeWithIndex; + +static bool +isOpenCLKernel(SPIRVFunction *BF) { + return BF->getModule()->isEntryPoint(ExecutionModelKernel, BF->getId()); +} + +static void +dumpLLVM(Module *M, const std::string &FName) { + std::error_code EC; + raw_fd_ostream FS(FName, EC, sys::fs::F_None); + if (EC) { + FS << *M; + FS.close(); + } +} + +static MDNode* +getMDNodeStringIntVec(LLVMContext *Context, + const std::vector<SPIRVWord>& IntVals) { + std::vector<Metadata*> ValueVec; + for (auto &I:IntVals) + ValueVec.push_back(ConstantAsMetadata::get( + ConstantInt::get(Type::getInt32Ty(*Context), I))); + return MDNode::get(*Context, ValueVec); +} + +static MDNode* +getMDTwoInt(LLVMContext *Context, unsigned Int1, unsigned Int2) { + std::vector<Metadata*> ValueVec; + ValueVec.push_back(ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(*Context), Int1))); + ValueVec.push_back(ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(*Context), Int2))); + return MDNode::get(*Context, ValueVec); +} + +static void +addOCLVersionMetadata(LLVMContext *Context, Module *M, + const std::string &MDName, unsigned Major, unsigned Minor) { + NamedMDNode *NamedMD = M->getOrInsertNamedMetadata(MDName); + NamedMD->addOperand(getMDTwoInt(Context, Major, Minor)); +} + +static void +addNamedMetadataStringSet(LLVMContext *Context, Module *M, + const std::string &MDName, const std::set<std::string> &StrSet) { + NamedMDNode *NamedMD = M->getOrInsertNamedMetadata(MDName); + std::vector<Metadata*> ValueVec; + for (auto &&Str : StrSet) { + ValueVec.push_back(MDString::get(*Context, Str)); + } + NamedMD->addOperand(MDNode::get(*Context, ValueVec)); +} + +static void +addOCLKernelArgumentMetadata(LLVMContext *Context, const std::string &MDName, + SPIRVFunction *BF, llvm::Function *Fn, + std::function<Metadata *(SPIRVFunctionParameter *)>Func) { + std::vector<Metadata*> ValueVec; + BF->foreachArgument([&](SPIRVFunctionParameter *Arg) { + ValueVec.push_back(Func(Arg)); + }); + Fn->setMetadata(MDName, MDNode::get(*Context, ValueVec)); +} + +class SPIRVToLLVMDbgTran { +public: + SPIRVToLLVMDbgTran(SPIRVModule *TBM, Module *TM) + :BM(TBM), M(TM), SpDbg(BM), Builder(*M){ + Enable = BM->hasDebugInfo(); + } + + void createCompileUnit() { + if (!Enable) + return; + auto File = SpDbg.getEntryPointFileStr(ExecutionModelKernel, 0); + std::string BaseName; + std::string Path; + splitFileName(File, BaseName, Path); + Builder.createCompileUnit(dwarf::DW_LANG_C99, + Builder.createFile(BaseName, Path), "spirv", false, "", 0, "", DICompileUnit::LineTablesOnly); + } + + void addDbgInfoVersion() { + if (!Enable) + return; + M->addModuleFlag(Module::Warning, "Dwarf Version", + dwarf::DWARF_VERSION); + M->addModuleFlag(Module::Warning, "Debug Info Version", + DEBUG_METADATA_VERSION); + } + + DIFile* getDIFile(const std::string &FileName){ + return getOrInsert(FileMap, FileName, [=]() -> DIFile* { + std::string BaseName; + std::string Path; + splitFileName(FileName, BaseName, Path); + if (!BaseName.empty()) + return Builder.createFile(BaseName, Path); + else + return nullptr; + }); + } + + DISubprogram* getDISubprogram(SPIRVFunction *SF, Function *F){ + return getOrInsert(FuncMap, F, [=](){ + auto DF = getDIFile(SpDbg.getFunctionFileStr(SF)); + auto FN = F->getName(); + auto LN = SpDbg.getFunctionLineNo(SF); + return Builder.createFunction(DF, FN, FN, DF, LN, + Builder.createSubroutineType(Builder.getOrCreateTypeArray(None)), + Function::isInternalLinkage(F->getLinkage()), + true, LN); + }); + } + + void transDbgInfo(SPIRVValue *SV, Value *V) { + if (!Enable || !SV->hasLine()) + return; + if (auto I = dyn_cast<Instruction>(V)) { + assert(SV->isInst() && "Invalid instruction"); + auto SI = static_cast<SPIRVInstruction *>(SV); + assert(SI->getParent() && + SI->getParent()->getParent() && + "Invalid instruction"); + auto Line = SV->getLine(); + I->setDebugLoc(DebugLoc::get(Line->getLine(), Line->getColumn(), + getDISubprogram(SI->getParent()->getParent(), + I->getParent()->getParent()))); + } + } + + void finalize() { + if (!Enable) + return; + Builder.finalize(); + } + +private: + SPIRVModule *BM; + Module *M; + SPIRVDbgInfo SpDbg; + DIBuilder Builder; + bool Enable; + std::unordered_map<std::string, DIFile *> FileMap; + std::unordered_map<Function *, DISubprogram *> FuncMap; + + void splitFileName(const std::string &FileName, + std::string &BaseName, + std::string &Path) { + auto Loc = FileName.find_last_of("/\\"); + if (Loc != std::string::npos) { + BaseName = FileName.substr(Loc + 1); + Path = FileName.substr(0, Loc); + } else { + BaseName = FileName; + Path = "."; + } + } +}; + +class SPIRVToLLVM { +public: + SPIRVToLLVM(Module *LLVMModule, SPIRVModule *TheSPIRVModule) + :M(LLVMModule), BM(TheSPIRVModule), DbgTran(BM, M){ + assert(M); + Context = &M->getContext(); + } + + std::string getOCLBuiltinName(SPIRVInstruction* BI); + std::string getOCLConvertBuiltinName(SPIRVInstruction *BI); + std::string getOCLGenericCastToPtrName(SPIRVInstruction *BI); + + Type *transType(SPIRVType *BT, bool IsClassMember = false); + std::string transTypeToOCLTypeName(SPIRVType *BT, bool IsSigned = true); + std::vector<Type *> transTypeVector(const std::vector<SPIRVType *>&); + bool translate(); + bool transAddressingModel(); + + Value *transValue(SPIRVValue *, Function *F, BasicBlock *, + bool CreatePlaceHolder = true); + Value *transValueWithoutDecoration(SPIRVValue *, Function *F, BasicBlock *, + bool CreatePlaceHolder = true); + Value *transDeviceEvent(SPIRVValue *BV, Function *F, BasicBlock *BB); + Value *transEnqueuedBlock(SPIRVValue *BF, SPIRVValue *BC, SPIRVValue *BCSize, + SPIRVValue *BCAligment, Function *F, BasicBlock *BB); + bool transDecoration(SPIRVValue *, Value *); + bool transAlign(SPIRVValue *, Value *); + Instruction *transOCLBuiltinFromExtInst(SPIRVExtInst *BC, BasicBlock *BB); + std::vector<Value *> transValue(const std::vector<SPIRVValue *>&, Function *F, + BasicBlock *); + Function *transFunction(SPIRVFunction *F); + Instruction *transEnqueueKernelBI(SPIRVInstruction *BI, BasicBlock *BB); + Instruction *transWGSizeBI(SPIRVInstruction *BI, BasicBlock *BB); + bool transFPContractMetadata(); + bool transKernelMetadata(); + bool transNonTemporalMetadata(Instruction *I); + bool transSourceLanguage(); + bool transSourceExtension(); + void transGeneratorMD(); + Value *transConvertInst(SPIRVValue* BV, Function* F, BasicBlock* BB); + Instruction *transBuiltinFromInst(const std::string& FuncName, + SPIRVInstruction* BI, BasicBlock* BB); + Instruction *transOCLBuiltinFromInst(SPIRVInstruction *BI, BasicBlock *BB); + Instruction *transSPIRVBuiltinFromInst(SPIRVInstruction *BI, BasicBlock *BB); + Instruction *transOCLBarrierFence(SPIRVInstruction* BI, BasicBlock *BB); + void transOCLVectorLoadStore(std::string& UnmangledName, + std::vector<SPIRVWord> &BArgs); + + /// Post-process translated LLVM module for OpenCL. + bool postProcessOCL(); + + /// \brief Post-process OpenCL builtin functions returning struct type. + /// + /// Some OpenCL builtin functions are translated to SPIR-V instructions with + /// struct type result, e.g. NDRange creation functions. Such functions + /// need to be post-processed to return the struct through sret argument. + bool postProcessOCLBuiltinReturnStruct(Function *F); + + /// \brief Post-process OpenCL builtin functions having array argument. + /// + /// These functions are translated to functions with array type argument + /// first, then post-processed to have pointer arguments. + bool postProcessOCLBuiltinWithArrayArguments(Function *F, + const std::string &DemangledName); + + /// \brief Post-process OpImageSampleExplicitLod. + /// sampled_image = __spirv_SampledImage__(image, sampler); + /// return __spirv_ImageSampleExplicitLod__(sampled_image, image_operands, + /// ...); + /// => + /// read_image(image, sampler, ...) + /// \return transformed call instruction. + Instruction *postProcessOCLReadImage(SPIRVInstruction *BI, CallInst *CI, + const std::string &DemangledName); + + /// \brief Post-process OpImageWrite. + /// return write_image(image, coord, color, image_operands, ...); + /// => + /// write_image(image, coord, ..., color) + /// \return transformed call instruction. + CallInst *postProcessOCLWriteImage(SPIRVInstruction *BI, CallInst *CI, + const std::string &DemangledName); + + /// \brief Post-process OpBuildNDRange. + /// OpBuildNDRange GlobalWorkSize, LocalWorkSize, GlobalWorkOffset + /// => + /// call ndrange_XD(GlobalWorkOffset, GlobalWorkSize, LocalWorkSize) + /// \return transformed call instruction. + CallInst *postProcessOCLBuildNDRange(SPIRVInstruction *BI, CallInst *CI, + const std::string &DemangledName); + + /// \brief Expand OCL builtin functions with scalar argument, e.g. + /// step, smoothstep. + /// gentype func (fp edge, gentype x) + /// => + /// gentype func (gentype edge, gentype x) + /// \return transformed call instruction. + CallInst *expandOCLBuiltinWithScalarArg(CallInst* CI, + const std::string &FuncName); + + /// \brief Post-process OpGroupAll and OpGroupAny instructions translation. + /// i1 func (<n x i1> arg) + /// => + /// i32 func (<n x i32> arg) + /// \return transformed call instruction. + Instruction *postProcessGroupAllAny(CallInst *CI, + const std::string &DemangledName); + + typedef DenseMap<SPIRVType *, Type *> SPIRVToLLVMTypeMap; + typedef DenseMap<SPIRVValue *, Value *> SPIRVToLLVMValueMap; + typedef DenseMap<SPIRVValue *, Value *> SPIRVBlockToLLVMStructMap; + typedef DenseMap<SPIRVFunction *, Function *> SPIRVToLLVMFunctionMap; + typedef DenseMap<GlobalVariable *, SPIRVBuiltinVariableKind> BuiltinVarMap; + + // A SPIRV value may be translated to a load instruction of a placeholder + // global variable. This map records load instruction of these placeholders + // which are supposed to be replaced by the real values later. + typedef std::map<SPIRVValue *, LoadInst*> SPIRVToLLVMPlaceholderMap; +private: + Module *M; + BuiltinVarMap BuiltinGVMap; + LLVMContext *Context; + SPIRVModule *BM; + SPIRVToLLVMTypeMap TypeMap; + SPIRVToLLVMValueMap ValueMap; + SPIRVToLLVMFunctionMap FuncMap; + SPIRVBlockToLLVMStructMap BlockMap; + SPIRVToLLVMPlaceholderMap PlaceholderMap; + SPIRVToLLVMDbgTran DbgTran; + + Type *mapType(SPIRVType *BT, Type *T) { + SPIRVDBG(dbgs() << *T << '\n';) + TypeMap[BT] = T; + return T; + } + + // If a value is mapped twice, the existing mapped value is a placeholder, + // which must be a load instruction of a global variable whose name starts + // with kPlaceholderPrefix. + Value *mapValue(SPIRVValue *BV, Value *V) { + auto Loc = ValueMap.find(BV); + if (Loc != ValueMap.end()) { + if (Loc->second == V) + return V; + auto LD = dyn_cast<LoadInst>(Loc->second); + auto Placeholder = dyn_cast<GlobalVariable>(LD->getPointerOperand()); + assert (LD && Placeholder && + Placeholder->getName().startswith(kPlaceholderPrefix) && + "A value is translated twice"); + // Replaces placeholders for PHI nodes + LD->replaceAllUsesWith(V); + LD->eraseFromParent(); + Placeholder->eraseFromParent(); + } + ValueMap[BV] = V; + return V; + } + + bool isSPIRVBuiltinVariable(GlobalVariable *GV, + SPIRVBuiltinVariableKind *Kind = nullptr) { + auto Loc = BuiltinGVMap.find(GV); + if (Loc == BuiltinGVMap.end()) + return false; + if (Kind) + *Kind = Loc->second; + return true; + } + // OpenCL function always has NoUnwound attribute. + // Change this if it is no longer true. + bool isFuncNoUnwind() const { return true;} + bool isSPIRVCmpInstTransToLLVMInst(SPIRVInstruction *BI) const; + bool transOCLBuiltinsFromVariables(); + bool transOCLBuiltinFromVariable(GlobalVariable *GV, + SPIRVBuiltinVariableKind Kind); + MDString *transOCLKernelArgTypeName(SPIRVFunctionParameter *); + + Value *mapFunction(SPIRVFunction *BF, Function *F) { + SPIRVDBG(spvdbgs() << "[mapFunction] " << *BF << " -> "; + dbgs() << *F << '\n';) + FuncMap[BF] = F; + return F; + } + + Value *getTranslatedValue(SPIRVValue *BV); + Type *getTranslatedType(SPIRVType *BT); + IntrinsicInst *getLifetimeStartIntrinsic(Instruction *I); + + SPIRVErrorLog &getErrorLog() { + return BM->getErrorLog(); + } + + void setCallingConv(CallInst *Call) { + Function *F = Call->getCalledFunction(); + assert(F); + Call->setCallingConv(F->getCallingConv()); + } + + void setAttrByCalledFunc(CallInst *Call); + Type *transFPType(SPIRVType* T); + BinaryOperator *transShiftLogicalBitwiseInst(SPIRVValue* BV, BasicBlock* BB, + Function* F); + void transFlags(llvm::Value* V); + Instruction *transCmpInst(SPIRVValue* BV, BasicBlock* BB, Function* F); + void transOCLBuiltinFromInstPreproc(SPIRVInstruction* BI, Type *&RetTy, + std::vector<SPIRVValue *> &Args); + Instruction* transOCLBuiltinPostproc(SPIRVInstruction* BI, + CallInst* CI, BasicBlock* BB, const std::string &DemangledName); + std::string transOCLImageTypeName(SPIRV::SPIRVTypeImage* ST); + std::string transOCLSampledImageTypeName(SPIRV::SPIRVTypeSampledImage* ST); + std::string transOCLPipeTypeName(SPIRV::SPIRVTypePipe* ST, + bool UseSPIRVFriendlyFormat = false, int PipeAccess = 0); + std::string transOCLPipeStorageTypeName(SPIRV::SPIRVTypePipeStorage* PST); + std::string transOCLImageTypeAccessQualifier(SPIRV::SPIRVTypeImage* ST); + std::string transOCLPipeTypeAccessQualifier(SPIRV::SPIRVTypePipe* ST); + + Value *oclTransConstantSampler(SPIRV::SPIRVConstantSampler* BCS); + Value * oclTransConstantPipeStorage(SPIRV::SPIRVConstantPipeStorage* BCPS); + void setName(llvm::Value* V, SPIRVValue* BV); + void setLLVMLoopMetadata(SPIRVLoopMerge* LM, BranchInst* BI); + void insertImageNameAccessQualifier(SPIRV::SPIRVTypeImage* ST, std::string &Name); + template<class Source, class Func> + bool foreachFuncCtlMask(Source, Func); + llvm::GlobalValue::LinkageTypes transLinkageType(const SPIRVValue* V); + Instruction *transOCLAllAny(SPIRVInstruction* BI, BasicBlock *BB); + Instruction *transOCLRelational(SPIRVInstruction* BI, BasicBlock *BB); + + CallInst *transOCLBarrier(BasicBlock *BB, SPIRVWord ExecScope, + SPIRVWord MemSema, SPIRVWord MemScope); + + CallInst *transOCLMemFence(BasicBlock *BB, + SPIRVWord MemSema, SPIRVWord MemScope); +}; + +Type * +SPIRVToLLVM::getTranslatedType(SPIRVType *BV){ + auto Loc = TypeMap.find(BV); + if (Loc != TypeMap.end()) + return Loc->second; + return nullptr; +} + +Value * +SPIRVToLLVM::getTranslatedValue(SPIRVValue *BV){ + auto Loc = ValueMap.find(BV); + if (Loc != ValueMap.end()) + return Loc->second; + return nullptr; +} + +IntrinsicInst * +SPIRVToLLVM::getLifetimeStartIntrinsic(Instruction *I) { + auto II = dyn_cast<IntrinsicInst>(I); + if (II && II->getIntrinsicID() == Intrinsic::lifetime_start) + return II; + // Bitcast might be inserted during translation of OpLifetimeStart + auto BC = dyn_cast<BitCastInst>(I); + if (BC) { + for (const auto &U : BC->users()) { + II = dyn_cast<IntrinsicInst>(U); + if (II && II->getIntrinsicID() == Intrinsic::lifetime_start) + return II;; + } + } + return nullptr; +} + +void +SPIRVToLLVM::setAttrByCalledFunc(CallInst *Call) { + Function *F = Call->getCalledFunction(); + assert(F); + if (F->isIntrinsic()) { + return; + } + Call->setCallingConv(F->getCallingConv()); + Call->setAttributes(F->getAttributes()); +} + +bool +SPIRVToLLVM::transOCLBuiltinsFromVariables(){ + std::vector<GlobalVariable *> WorkList; + for (auto I = M->global_begin(), E = M->global_end(); I != E; ++I) { + SPIRVBuiltinVariableKind Kind; + if (!isSPIRVBuiltinVariable(&(*I), &Kind)) + continue; + if (!transOCLBuiltinFromVariable(&(*I), Kind)) + return false; + WorkList.push_back(&(*I)); + } + for (auto &I:WorkList) { + I->eraseFromParent(); + } + return true; +} + +// For integer types shorter than 32 bit, unsigned/signedness can be inferred +// from zext/sext attribute. +MDString * +SPIRVToLLVM::transOCLKernelArgTypeName(SPIRVFunctionParameter *Arg) { + auto Ty = Arg->isByVal() ? Arg->getType()->getPointerElementType() : + Arg->getType(); + return MDString::get(*Context, transTypeToOCLTypeName(Ty, !Arg->isZext())); +} + +// Variable like GlobalInvolcationId[x] -> get_global_id(x). +// Variable like WorkDim -> get_work_dim(). +bool +SPIRVToLLVM::transOCLBuiltinFromVariable(GlobalVariable *GV, + SPIRVBuiltinVariableKind Kind) { + std::string FuncName = SPIRSPIRVBuiltinVariableMap::rmap(Kind); + std::string MangledName; + Type *ReturnTy = GV->getType()->getPointerElementType(); + bool IsVec = ReturnTy->isVectorTy(); + if (IsVec) + ReturnTy = cast<VectorType>(ReturnTy)->getElementType(); + std::vector<Type*> ArgTy; + if (IsVec) + ArgTy.push_back(Type::getInt32Ty(*Context)); + MangleOpenCLBuiltin(FuncName, ArgTy, MangledName); + Function *Func = M->getFunction(MangledName); + if (!Func) { + FunctionType *FT = FunctionType::get(ReturnTy, ArgTy, false); + Func = Function::Create(FT, GlobalValue::ExternalLinkage, MangledName, M); + Func->setCallingConv(CallingConv::SPIR_FUNC); + Func->addFnAttr(Attribute::NoUnwind); + Func->addFnAttr(Attribute::ReadNone); + } + std::vector<Instruction *> Deletes; + std::vector<Instruction *> Uses; + for (auto UI = GV->user_begin(), UE = GV->user_end(); UI != UE; ++UI) { + assert (isa<LoadInst>(*UI) && "Unsupported use"); + auto LD = dyn_cast<LoadInst>(*UI); + if (!IsVec) { + Uses.push_back(LD); + Deletes.push_back(LD); + continue; + } + for (auto LDUI = LD->user_begin(), LDUE = LD->user_end(); LDUI != LDUE; + ++LDUI) { + assert(isa<ExtractElementInst>(*LDUI) && "Unsupported use"); + auto EEI = dyn_cast<ExtractElementInst>(*LDUI); + Uses.push_back(EEI); + Deletes.push_back(EEI); + } + Deletes.push_back(LD); + } + for (auto &I:Uses) { + std::vector<Value *> Arg; + if (auto EEI = dyn_cast<ExtractElementInst>(I)) + Arg.push_back(EEI->getIndexOperand()); + auto Call = CallInst::Create(Func, Arg, "", I); + Call->takeName(I); + setAttrByCalledFunc(Call); + SPIRVDBG(dbgs() << "[transOCLBuiltinFromVariable] " << *I << " -> " << + *Call << '\n';) + I->replaceAllUsesWith(Call); + } + for (auto &I:Deletes) { + I->eraseFromParent(); + } + return true; +} + +Type * +SPIRVToLLVM::transFPType(SPIRVType* T) { + switch(T->getFloatBitWidth()) { + case 16: return Type::getHalfTy(*Context); + case 32: return Type::getFloatTy(*Context); + case 64: return Type::getDoubleTy(*Context); + default: + llvm_unreachable("Invalid type"); + return nullptr; + } +} + +std::string +SPIRVToLLVM::transOCLImageTypeName(SPIRV::SPIRVTypeImage* ST) { + std::string Name = std::string(kSPR2TypeName::OCLPrefix) + + rmap<std::string>(ST->getDescriptor()); + if (SPIRVGenImgTypeAccQualPostfix) + SPIRVToLLVM::insertImageNameAccessQualifier(ST, Name); + return std::move(Name); +} + +std::string +SPIRVToLLVM::transOCLSampledImageTypeName(SPIRV::SPIRVTypeSampledImage* ST) { + return getSPIRVTypeName(kSPIRVTypeName::SampledImg, + getSPIRVImageTypePostfixes(getSPIRVImageSampledTypeName( + ST->getImageType()->getSampledType()), + ST->getImageType()->getDescriptor(), + ST->getImageType()->hasAccessQualifier() ? + ST->getImageType()->getAccessQualifier() : + AccessQualifierReadOnly)); +} + +std::string +SPIRVToLLVM::transOCLPipeTypeName(SPIRV::SPIRVTypePipe* PT, + bool UseSPIRVFriendlyFormat, int PipeAccess){ + if (!UseSPIRVFriendlyFormat) + return kSPR2TypeName::Pipe; + else + return std::string(kSPIRVTypeName::PrefixAndDelim) + + kSPIRVTypeName::Pipe + + kSPIRVTypeName::Delimiter + + kSPIRVTypeName::PostfixDelim + + PipeAccess; +} + +std::string +SPIRVToLLVM::transOCLPipeStorageTypeName(SPIRV::SPIRVTypePipeStorage* PST) { + return std::string(kSPIRVTypeName::PrefixAndDelim) + + kSPIRVTypeName::PipeStorage; +} + +Type * +SPIRVToLLVM::transType(SPIRVType *T, bool IsClassMember) { + auto Loc = TypeMap.find(T); + if (Loc != TypeMap.end()) + return Loc->second; + + SPIRVDBG(spvdbgs() << "[transType] " << *T << " -> ";) + T->validate(); + switch(T->getOpCode()) { + case OpTypeVoid: + return mapType(T, Type::getVoidTy(*Context)); + case OpTypeBool: + return mapType(T, Type::getInt1Ty(*Context)); + case OpTypeInt: + return mapType(T, Type::getIntNTy(*Context, T->getIntegerBitWidth())); + case OpTypeFloat: + return mapType(T, transFPType(T)); + case OpTypeArray: + return mapType(T, ArrayType::get(transType(T->getArrayElementType()), + T->getArrayLength())); + case OpTypePointer: + return mapType(T, PointerType::get(transType( + T->getPointerElementType(), IsClassMember), + SPIRSPIRVAddrSpaceMap::rmap(T->getPointerStorageClass()))); + case OpTypeVector: + return mapType(T, VectorType::get(transType(T->getVectorComponentType()), + T->getVectorComponentCount())); + case OpTypeOpaque: + return mapType(T, StructType::create(*Context, T->getName())); + case OpTypeFunction: { + auto FT = static_cast<SPIRVTypeFunction *>(T); + auto RT = transType(FT->getReturnType()); + std::vector<Type *> PT; + for (size_t I = 0, E = FT->getNumParameters(); I != E; ++I) + PT.push_back(transType(FT->getParameterType(I))); + return mapType(T, FunctionType::get(RT, PT, false)); + } + case OpTypeImage: { + auto ST = static_cast<SPIRVTypeImage *>(T); + if (ST->isOCLImage()) + return mapType(T, getOrCreateOpaquePtrType(M, + transOCLImageTypeName(ST))); + else + llvm_unreachable("Unsupported image type"); + return nullptr; + } + case OpTypeSampler: + return mapType(T, Type::getInt32Ty(*Context)); + case OpTypeSampledImage: { + auto ST = static_cast<SPIRVTypeSampledImage *>(T); + return mapType(T, getOrCreateOpaquePtrType(M, + transOCLSampledImageTypeName(ST))); + } + case OpTypeStruct: { + auto ST = static_cast<SPIRVTypeStruct *>(T); + auto Name = ST->getName(); + if (!Name.empty()) { + if (auto OldST = M->getTypeByName(Name)) + OldST->setName(""); + } + auto *StructTy = StructType::create(*Context, Name); + mapType(ST, StructTy); + SmallVector<Type *, 4> MT; + for (size_t I = 0, E = ST->getMemberCount(); I != E; ++I) + MT.push_back(transType(ST->getMemberType(I), true)); + StructTy->setBody(MT, ST->isPacked()); + return StructTy; + } + case OpTypePipe: { + auto PT = static_cast<SPIRVTypePipe *>(T); + return mapType(T, getOrCreateOpaquePtrType(M, + transOCLPipeTypeName(PT, IsClassMember, PT->getAccessQualifier()), + getOCLOpaqueTypeAddrSpace(T->getOpCode()))); + + } + case OpTypePipeStorage: { + auto PST = static_cast<SPIRVTypePipeStorage *>(T); + return mapType(T, getOrCreateOpaquePtrType(M, + transOCLPipeStorageTypeName(PST), + getOCLOpaqueTypeAddrSpace(T->getOpCode()))); + } + default: { + auto OC = T->getOpCode(); + if (isOpaqueGenericTypeOpCode(OC)) + return mapType(T, getOrCreateOpaquePtrType(M, + OCLOpaqueTypeOpCodeMap::rmap(OC), + getOCLOpaqueTypeAddrSpace(OC))); + llvm_unreachable("Not implemented"); + } + } + return 0; +} + + +std::string +SPIRVToLLVM::transTypeToOCLTypeName(SPIRVType *T, bool IsSigned) { + switch(T->getOpCode()) { + case OpTypeVoid: + return "void"; + case OpTypeBool: + return "bool"; + case OpTypeInt: { + std::string Prefix = IsSigned ? "" : "u"; + switch(T->getIntegerBitWidth()) { + case 8: + return Prefix + "char"; + case 16: + return Prefix + "short"; + case 32: + return Prefix + "int"; + case 64: + return Prefix + "long"; default: - case AccessQualifierReadOnly: Suffix = "_read"; break;
- case AccessQualifierWriteOnly: Suffix = "_write"; break;
- case AccessQualifierReadWrite: Suffix = "_read_write"; break;
- }
- }
-
- return transBuiltinFromInst(getSPIRVFuncName(BI->getOpCode(), Suffix), BI, BB);
-}
-
-bool
-SPIRVToLLVM::translate() {
- if (!transAddressingModel())
- return false;
-
- DbgTran.createCompileUnit();
- DbgTran.addDbgInfoVersion();
-
- for (unsigned I = 0, E = BM->getNumVariables(); I != E; ++I) {
- auto BV = BM->getVariable(I);
- if (BV->getStorageClass() != StorageClassFunction)
- transValue(BV, nullptr, nullptr);
- }
-
- for (unsigned I = 0, E = BM->getNumFunctions(); I != E; ++I) {
- transFunction(BM->getFunction(I));
- }
- if (!transKernelMetadata())
- return false;
- if (!transFPContractMetadata())
- return false;
- if (!transSourceLanguage())
- return false;
- if (!transSourceExtension())
- return false;
- transGeneratorMD();
- if (!transOCLBuiltinsFromVariables())
- return false;
- if (!postProcessOCL())
- return false;
- eraseUselessFunctions(M);
- DbgTran.finalize();
- return true;
-}
-
-bool
-SPIRVToLLVM::transAddressingModel() {
- switch (BM->getAddressingModel()) {
- case AddressingModelPhysical64:
- M->setTargetTriple(SPIR_TARGETTRIPLE64);
- M->setDataLayout(SPIR_DATALAYOUT64);
- break;
- case AddressingModelPhysical32:
- M->setTargetTriple(SPIR_TARGETTRIPLE32);
- M->setDataLayout(SPIR_DATALAYOUT32);
- break;
- case AddressingModelLogical:
- // Do not set target triple and data layout
- break;
- default:
- SPIRVCKRT(0, InvalidAddressingModel, "Actual addressing mode is " +
- (unsigned)BM->getAddressingModel());
- }
- return true;
-}
-
-bool
-SPIRVToLLVM::transDecoration(SPIRVValue *BV, Value *V) {
- if (!transAlign(BV, V))
- return false;
- DbgTran.transDbgInfo(BV, V);
- return true;
-}
-
-bool
-SPIRVToLLVM::transFPContractMetadata() {
- bool ContractOff = false;
- for (unsigned I = 0, E = BM->getNumFunctions(); I != E; ++I) {
- SPIRVFunction *BF = BM->getFunction(I);
- if (!isOpenCLKernel(BF))
- continue;
- if (BF->getExecutionMode(ExecutionModeContractionOff)) {
- ContractOff = true;
- break;
- }
- }
- if (!ContractOff)
- M->getOrInsertNamedMetadata(kSPIR2MD::FPContract);
- return true;
-}
-
-std::string SPIRVToLLVM::transOCLImageTypeAccessQualifier(
- SPIRV::SPIRVTypeImage* ST) {
- return SPIRSPIRVAccessQualifierMap::rmap(ST->hasAccessQualifier() ?
- ST->getAccessQualifier() : AccessQualifierReadOnly);
-}
-
-bool
-SPIRVToLLVM::transNonTemporalMetadata(Instruction *I) {
- Constant* One = ConstantInt::get(Type::getInt32Ty(*Context), 1);
- MDNode *Node = MDNode::get(*Context, ConstantAsMetadata::get(One));
- I->setMetadata(M->getMDKindID("nontemporal"), Node);
- return true;
-}
-
-bool
-SPIRVToLLVM::transKernelMetadata() {
- for (unsigned I = 0, E = BM->getNumFunctions(); I != E; ++I) {
- SPIRVFunction *BF = BM->getFunction(I);
- Function *F = static_cast<Function *>(getTranslatedValue(BF));
- assert(F && "Invalid translated function");
- if (F->getCallingConv() != CallingConv::SPIR_KERNEL)
- continue;
-
- // Generate metadata for kernel_arg_address_spaces
- addOCLKernelArgumentMetadata(Context, SPIR_MD_KERNEL_ARG_ADDR_SPACE, BF, F,
- [=](SPIRVFunctionParameter *Arg){
- SPIRVType *ArgTy = Arg->getType();
- SPIRAddressSpace AS = SPIRAS_Private;
- if (ArgTy->isTypePointer())
- AS = SPIRSPIRVAddrSpaceMap::rmap(ArgTy->getPointerStorageClass());
- else if (ArgTy->isTypeOCLImage() || ArgTy->isTypePipe())
- AS = SPIRAS_Global;
- return ConstantAsMetadata::get(
- ConstantInt::get(Type::getInt32Ty(*Context), AS));
- });
- // Generate metadata for kernel_arg_access_qual
- addOCLKernelArgumentMetadata(Context, SPIR_MD_KERNEL_ARG_ACCESS_QUAL, BF, F,
- [=](SPIRVFunctionParameter *Arg){
- std::string Qual;
- auto T = Arg->getType();
- if (T->isTypeOCLImage()) {
- auto ST = static_cast<SPIRVTypeImage *>(T);
- Qual = transOCLImageTypeAccessQualifier(ST);
- } else if (T->isTypePipe()){
- auto PT = static_cast<SPIRVTypePipe *>(T);
- Qual = transOCLPipeTypeAccessQualifier(PT);
- } else
- Qual = "none";
- return MDString::get(*Context, Qual);
- });
- // Generate metadata for kernel_arg_type
- addOCLKernelArgumentMetadata(Context, SPIR_MD_KERNEL_ARG_TYPE, BF, F,
- [=](SPIRVFunctionParameter *Arg){
- return transOCLKernelArgTypeName(Arg);
- });
- // Generate metadata for kernel_arg_type_qual
- addOCLKernelArgumentMetadata(Context, SPIR_MD_KERNEL_ARG_TYPE_QUAL, BF, F,
- [=](SPIRVFunctionParameter *Arg){
- std::string Qual;
- if (Arg->hasDecorate(DecorationVolatile))
- Qual = kOCLTypeQualifierName::Volatile;
- Arg->foreachAttr([&](SPIRVFuncParamAttrKind Kind){
- Qual += Qual.empty() ? "" : " ";
- switch(Kind){
- case FunctionParameterAttributeNoAlias:
- Qual += kOCLTypeQualifierName::Restrict;
- break;
- case FunctionParameterAttributeNoWrite:
- Qual += kOCLTypeQualifierName::Const;
- break;
- default:
- // do nothing.
- break;
- }
- });
- if (Arg->getType()->isTypePipe()) {
- Qual += Qual.empty() ? "" : " ";
- Qual += kOCLTypeQualifierName::Pipe;
- }
- return MDString::get(*Context, Qual);
- });
- // Generate metadata for kernel_arg_base_type
- addOCLKernelArgumentMetadata(Context, SPIR_MD_KERNEL_ARG_BASE_TYPE, BF, F,
- [=](SPIRVFunctionParameter *Arg){
- return transOCLKernelArgTypeName(Arg);
- });
- // Generate metadata for kernel_arg_name
- if (SPIRVGenKernelArgNameMD) {
- bool ArgHasName = true;
- BF->foreachArgument([&](SPIRVFunctionParameter *Arg){
- ArgHasName &= !Arg->getName().empty();
- });
- if (ArgHasName)
- addOCLKernelArgumentMetadata(Context, SPIR_MD_KERNEL_ARG_NAME, BF, F,
- [=](SPIRVFunctionParameter *Arg){
- return MDString::get(*Context, Arg->getName());
- });
- }
- // Generate metadata for reqd_work_group_size
- if (auto EM = BF->getExecutionMode(ExecutionModeLocalSize)) {
- F->setMetadata(kSPIR2MD::WGSize,
- getMDNodeStringIntVec(Context, EM->getLiterals()));
- }
- // Generate metadata for work_group_size_hint
- if (auto EM = BF->getExecutionMode(ExecutionModeLocalSizeHint)) {
- F->setMetadata(kSPIR2MD::WGSizeHint,
- getMDNodeStringIntVec(Context, EM->getLiterals()));
- }
- // Generate metadata for vec_type_hint
- if (auto EM = BF->getExecutionMode(ExecutionModeVecTypeHint)) {
- std::vector<Metadata*> MetadataVec;
- Type *VecHintTy = decodeVecTypeHint(*Context, EM->getLiterals()[0]);
- assert(VecHintTy);
- MetadataVec.push_back(ValueAsMetadata::get(UndefValue::get(VecHintTy)));
- MetadataVec.push_back(
- ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(*Context),
- 1)));
- F->setMetadata(kSPIR2MD::VecTyHint, MDNode::get(*Context, MetadataVec));
- }
- }
- return true;
-}
-
-bool
-SPIRVToLLVM::transAlign(SPIRVValue *BV, Value *V) {
- if (auto AL = dyn_cast<AllocaInst>(V)) {
- SPIRVWord Align = 0;
- if (BV->hasAlignment(&Align))
- AL->setAlignment(Align);
- return true;
- }
- if (auto GV = dyn_cast<GlobalVariable>(V)) {
- SPIRVWord Align = 0;
- if (BV->hasAlignment(&Align))
- GV->setAlignment(Align);
- return true;
- }
- return true;
-}
-
-void
-SPIRVToLLVM::transOCLVectorLoadStore(std::string& UnmangledName,
- std::vector<SPIRVWord> &BArgs) {
- if (UnmangledName.find("vload") == 0 &&
- UnmangledName.find("n") != std::string::npos) {
- if (BArgs.back() != 1) {
- std::stringstream SS;
- SS << BArgs.back();
- UnmangledName.replace(UnmangledName.find("n"), 1, SS.str());
- } else {
- UnmangledName.erase(UnmangledName.find("n"), 1);
- }
- BArgs.pop_back();
- } else if (UnmangledName.find("vstore") == 0) {
- if (UnmangledName.find("n") != std::string::npos) {
- auto T = BM->getValueType(BArgs[0]);
- if (T->isTypeVector()) {
- auto W = T->getVectorComponentCount();
- std::stringstream SS;
- SS << W;
- UnmangledName.replace(UnmangledName.find("n"), 1, SS.str());
- } else {
- UnmangledName.erase(UnmangledName.find("n"), 1);
- }
- }
- if (UnmangledName.find("_r") != std::string::npos) {
- UnmangledName.replace(UnmangledName.find("_r"), 2, std::string("_") +
- SPIRSPIRVFPRoundingModeMap::rmap(static_cast<SPIRVFPRoundingModeKind>(
- BArgs.back())));
- BArgs.pop_back();
- }
- }
-}
-
-// printf is not mangled. The function type should have just one argument.
-// read_image*: the second argument should be mangled as sampler.
-Instruction *
-SPIRVToLLVM::transOCLBuiltinFromExtInst(SPIRVExtInst *BC, BasicBlock *BB) {
- assert(BB && "Invalid BB");
- std::string MangledName;
- SPIRVWord EntryPoint = BC->getExtOp();
- bool IsVarArg = false;
- bool IsPrintf = false;
- std::string UnmangledName;
- auto BArgs = BC->getArguments();
-
- assert(BM->getBuiltinSet(BC->getExtSetId()) == SPIRVEIS_OpenCL &&
- "Not OpenCL extended instruction");
- if (EntryPoint == OpenCLLIB::Printf)
- IsPrintf = true;
- else {
- UnmangledName = OCLExtOpMap::map(static_cast<OCLExtOpKind>(
- EntryPoint));
- }
-
- SPIRVDBG(spvdbgs() << "[transOCLBuiltinFromExtInst] OrigUnmangledName: " <<
- UnmangledName << '\n');
- transOCLVectorLoadStore(UnmangledName, BArgs);
-
- std::vector<Type *> ArgTypes = transTypeVector(BC->getValueTypes(BArgs));
-
- if (IsPrintf) {
- MangledName = "printf";
- IsVarArg = true;
- ArgTypes.resize(1);
- } else if (UnmangledName.find("read_image") == 0) {
- auto ModifiedArgTypes = ArgTypes;
- ModifiedArgTypes[1] = getOrCreateOpaquePtrType(M, "opencl.sampler_t");
- MangleOpenCLBuiltin(UnmangledName, ModifiedArgTypes, MangledName);
- } else {
- MangleOpenCLBuiltin(UnmangledName, ArgTypes, MangledName);
- }
- SPIRVDBG(spvdbgs() << "[transOCLBuiltinFromExtInst] ModifiedUnmangledName: " <<
- UnmangledName << " MangledName: " << MangledName << '\n');
-
- FunctionType *FT = FunctionType::get(
- transType(BC->getType()),
- ArgTypes,
- IsVarArg);
- Function *F = M->getFunction(MangledName);
- if (!F) {
- F = Function::Create(FT,
- GlobalValue::ExternalLinkage,
- MangledName,
- M);
- F->setCallingConv(CallingConv::SPIR_FUNC);
- if (isFuncNoUnwind())
- F->addFnAttr(Attribute::NoUnwind);
- }
- auto Args = transValue(BC->getValues(BArgs), F, BB);
- SPIRVDBG(dbgs() << "[transOCLBuiltinFromExtInst] Function: " << *F <<
- ", Args: ";
- for (auto &I:Args) dbgs() << *I << ", "; dbgs() << '\n');
- CallInst *Call = CallInst::Create(F,
- Args,
- BC->getName(),
- BB);
- setCallingConv(Call);
- addFnAttr(Context, Call, Attribute::NoUnwind);
- return transOCLBuiltinPostproc(BC, Call, BB, UnmangledName);
-}
-
-CallInst *
-SPIRVToLLVM::transOCLBarrier(BasicBlock *BB, SPIRVWord ExecScope,
- SPIRVWord MemSema, SPIRVWord MemScope) {
- SPIRVWord Ver = 0;
- BM->getSourceLanguage(&Ver);
-
- Type* Int32Ty = Type::getInt32Ty(*Context);
- Type* VoidTy = Type::getVoidTy(*Context);
-
- std::string FuncName;
- SmallVector<Type *, 2> ArgTy;
- SmallVector<Value *, 2> Arg;
-
- Constant *MemFenceFlags =
- ConstantInt::get(Int32Ty, rmapBitMask<OCLMemFenceMap>(MemSema));
-
- FuncName = (ExecScope == ScopeWorkgroup) ? kOCLBuiltinName::WorkGroupBarrier
- : kOCLBuiltinName::SubGroupBarrier;
-
- if (ExecScope == ScopeWorkgroup && Ver > 0 && Ver <= kOCLVer::CL12) {
- FuncName = kOCLBuiltinName::Barrier;
- ArgTy.push_back(Int32Ty);
- Arg.push_back(MemFenceFlags);
- } else {
- Constant *Scope = ConstantInt::get(Int32Ty, OCLMemScopeMap::rmap(
- static_cast<spv::Scope>(MemScope)));
-
- ArgTy.append(2, Int32Ty);
- Arg.push_back(MemFenceFlags);
- Arg.push_back(Scope);
- }
-
- std::string MangledName;
-
- MangleOpenCLBuiltin(FuncName, ArgTy, MangledName);
- Function *Func = M->getFunction(MangledName);
- if (!Func) {
- FunctionType *FT = FunctionType::get(VoidTy, ArgTy, false);
- Func = Function::Create(FT, GlobalValue::ExternalLinkage, MangledName, M);
- Func->setCallingConv(CallingConv::SPIR_FUNC);
- if (isFuncNoUnwind())
- Func->addFnAttr(Attribute::NoUnwind);
- }
-
- return CallInst::Create(Func, Arg, "", BB);
-}
-
-CallInst *
-SPIRVToLLVM::transOCLMemFence(BasicBlock *BB,
- SPIRVWord MemSema, SPIRVWord MemScope) {
- SPIRVWord Ver = 0;
- BM->getSourceLanguage(&Ver);
-
- Type* Int32Ty = Type::getInt32Ty(*Context);
- Type* VoidTy = Type::getVoidTy(*Context);
-
- std::string FuncName;
- SmallVector<Type *, 3> ArgTy;
- SmallVector<Value *, 3> Arg;
-
- Constant *MemFenceFlags =
- ConstantInt::get(Int32Ty, rmapBitMask<OCLMemFenceMap>(MemSema));
-
- if (Ver > 0 && Ver <= kOCLVer::CL12) {
- FuncName = kOCLBuiltinName::MemFence;
- ArgTy.push_back(Int32Ty);
- Arg.push_back(MemFenceFlags);
- } else {
- Constant *Order =
- ConstantInt::get(Int32Ty, mapSPIRVMemOrderToOCL(MemSema));
-
- Constant *Scope = ConstantInt::get(Int32Ty, OCLMemScopeMap::rmap(
- static_cast<spv::Scope>(MemScope)));
-
- FuncName = kOCLBuiltinName::AtomicWorkItemFence;
- ArgTy.append(3, Int32Ty);
- Arg.push_back(MemFenceFlags);
- Arg.push_back(Order);
- Arg.push_back(Scope);
- }
-
- std::string MangledName;
-
- MangleOpenCLBuiltin(FuncName, ArgTy, MangledName);
- Function *Func = M->getFunction(MangledName);
- if (!Func) {
- FunctionType *FT = FunctionType::get(VoidTy, ArgTy, false);
- Func = Function::Create(FT, GlobalValue::ExternalLinkage, MangledName, M);
- Func->setCallingConv(CallingConv::SPIR_FUNC);
- if (isFuncNoUnwind())
- Func->addFnAttr(Attribute::NoUnwind);
- }
-
- return CallInst::Create(Func, Arg, "", BB);
-}
-
-Instruction *
-SPIRVToLLVM::transOCLBarrierFence(SPIRVInstruction *MB, BasicBlock *BB) {
- assert(BB && "Invalid BB");
- std::string FuncName;
- auto getIntVal = [](SPIRVValue *value){
- return static_cast<SPIRVConstant*>(value)->getZExtIntValue();
- };
-
- CallInst* Call = nullptr;
-
- if (MB->getOpCode() == OpMemoryBarrier) {
- auto MemB = static_cast<SPIRVMemoryBarrier*>(MB);
-
- SPIRVWord MemScope = getIntVal(MemB->getOpValue(0));
- SPIRVWord MemSema = getIntVal(MemB->getOpValue(1));
-
- Call = transOCLMemFence(BB, MemSema, MemScope);
- } else if (MB->getOpCode() == OpControlBarrier) {
- auto CtlB = static_cast<SPIRVControlBarrier*>(MB);
-
- SPIRVWord ExecScope = getIntVal(CtlB->getExecScope());
- SPIRVWord MemSema = getIntVal(CtlB->getMemSemantic());
- SPIRVWord MemScope = getIntVal(CtlB->getMemScope());
-
- Call = transOCLBarrier(BB, ExecScope, MemSema, MemScope);
- } else {
- llvm_unreachable("Invalid instruction");
- }
-
- setName(Call, MB);
- setAttrByCalledFunc(Call);
- SPIRVDBG(spvdbgs() << "[transBarrier] " << *MB << " -> ";
- dbgs() << *Call << '\n';)
-
- return Call;
-}
-
-// SPIR-V only contains language version. Use OpenCL language version as
-// SPIR version.
-bool
-SPIRVToLLVM::transSourceLanguage() {
- SPIRVWord Ver = 0;
- SourceLanguage Lang = BM->getSourceLanguage(&Ver);
- assert((Lang == SourceLanguageOpenCL_C ||
- Lang == SourceLanguageOpenCL_CPP) && "Unsupported source language");
- unsigned short Major = 0;
- unsigned char Minor = 0;
- unsigned char Rev = 0;
- std::tie(Major, Minor, Rev) = decodeOCLVer(Ver);
- SPIRVMDBuilder Builder(*M);
- Builder.addNamedMD(kSPIRVMD::Source)
- .addOp()
- .add(Lang)
- .add(Ver)
- .done();
- // ToDo: Phasing out usage of old SPIR metadata
- if (Ver <= kOCLVer::CL12)
- addOCLVersionMetadata(Context, M, kSPIR2MD::SPIRVer, 1, 2);
- else
- addOCLVersionMetadata(Context, M, kSPIR2MD::SPIRVer, 2, 0);
-
- addOCLVersionMetadata(Context, M, kSPIR2MD::OCLVer, Major, Minor);
- return true;
-}
-
-bool
-SPIRVToLLVM::transSourceExtension() {
- auto ExtSet = rmap<OclExt::Kind>(BM->getExtension());
- auto CapSet = rmap<OclExt::Kind>(BM->getCapability());
- ExtSet.insert(CapSet.begin(), CapSet.end());
- auto OCLExtensions = map<std::string>(ExtSet);
- std::set<std::string> OCLOptionalCoreFeatures;
- static const char *OCLOptCoreFeatureNames[] = {
- "cl_images", "cl_doubles",
- };
- for (auto &I : OCLOptCoreFeatureNames) {
- auto Loc = OCLExtensions.find(I);
- if (Loc != OCLExtensions.end()) {
- OCLExtensions.erase(Loc);
- OCLOptionalCoreFeatures.insert(I);
- }
- }
- addNamedMetadataStringSet(Context, M, kSPIR2MD::Extensions, OCLExtensions);
- addNamedMetadataStringSet(Context, M, kSPIR2MD::OptFeatures,
- OCLOptionalCoreFeatures);
- return true;
-}
-
-// If the argument is unsigned return uconvert*, otherwise return convert*.
-std::string
-SPIRVToLLVM::getOCLConvertBuiltinName(SPIRVInstruction* BI) {
- auto OC = BI->getOpCode();
- assert(isCvtOpCode(OC) && "Not convert instruction");
- auto U = static_cast<SPIRVUnary *>(BI);
- std::string Name;
- if (isCvtFromUnsignedOpCode(OC))
- Name = "u";
- Name += "convert_";
- Name += mapSPIRVTypeToOCLType(U->getType(),
- !isCvtToUnsignedOpCode(OC));
- SPIRVFPRoundingModeKind Rounding;
- if (U->isSaturatedConversion())
- Name += "_sat";
- if (U->hasFPRoundingMode(&Rounding)) {
- Name += "_";
- Name += SPIRSPIRVFPRoundingModeMap::rmap(Rounding);
- }
- return Name;
-}
-
-//Check Address Space of the Pointer Type
-std::string
-SPIRVToLLVM::getOCLGenericCastToPtrName(SPIRVInstruction* BI) {
- auto GenericCastToPtrInst = BI->getType()->getPointerStorageClass();
- switch (GenericCastToPtrInst) {
- case StorageClassCrossWorkgroup:
- return std::string(kOCLBuiltinName::ToGlobal);
- case StorageClassWorkgroup:
- return std::string(kOCLBuiltinName::ToLocal);
- case StorageClassFunction:
- return std::string(kOCLBuiltinName::ToPrivate);
- default:
- llvm_unreachable("Invalid address space");
- return "";
- }
-}
-
-llvm::GlobalValue::LinkageTypes
-SPIRVToLLVM::transLinkageType(const SPIRVValue* V) {
- if (V->getLinkageType() == LinkageTypeInternal) {
- return GlobalValue::InternalLinkage;
- }
- else if (V->getLinkageType() == LinkageTypeImport) {
- // Function declaration
- if (V->getOpCode() == OpFunction) {
- if (static_cast<const SPIRVFunction*>(V)->getNumBasicBlock() == 0)
- return GlobalValue::ExternalLinkage;
- }
- // Variable declaration
- if (V->getOpCode() == OpVariable) {
- if (static_cast<const SPIRVVariable*>(V)->getInitializer() == 0)
- return GlobalValue::ExternalLinkage;
- }
- // Definition
- return GlobalValue::AvailableExternallyLinkage;
- }
- else {// LinkageTypeExport
- if (V->getOpCode() == OpVariable) {
- if (static_cast<const SPIRVVariable*>(V)->getInitializer() == 0 )
- // Tentative definition
- return GlobalValue::CommonLinkage;
- }
- return GlobalValue::ExternalLinkage;
- }
-}
-
-Instruction *SPIRVToLLVM::transOCLAllAny(SPIRVInstruction *I, BasicBlock *BB) {
- CallInst *CI = cast<CallInst>(transSPIRVBuiltinFromInst(I, BB));
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- return cast<Instruction>(mapValue(
- I, mutateCallInstOCL(
- M, CI,
- [=](CallInst *, std::vector<Value *> &Args, llvm::Type *&RetTy) {
- Type *Int32Ty = Type::getInt32Ty(*Context);
- auto OldArg = CI->getOperand(0);
- auto NewArgTy = VectorType::get(
- Int32Ty, OldArg->getType()->getVectorNumElements());
- auto NewArg =
- CastInst::CreateSExtOrBitCast(OldArg, NewArgTy, "", CI);
- Args[0] = NewArg;
- RetTy = Int32Ty;
- return CI->getCalledFunction()->getName();
- },
- [=](CallInst *NewCI) -> Instruction * {
- return CastInst::CreateTruncOrBitCast(
- NewCI, Type::getInt1Ty(*Context), "", NewCI->getNextNode());
- },
- &Attrs)));
-}
-
-Instruction *SPIRVToLLVM::transOCLRelational(SPIRVInstruction *I, BasicBlock *BB) {
- CallInst *CI = cast<CallInst>(transSPIRVBuiltinFromInst(I, BB));
- AttributeList Attrs = CI->getCalledFunction()->getAttributes();
- return cast<Instruction>(mapValue(
- I, mutateCallInstOCL(
- M, CI,
- [=](CallInst *, std::vector<Value *> &Args, llvm::Type *&RetTy) {
- Type *IntTy = Type::getInt32Ty(*Context);
- RetTy = IntTy;
- if (CI->getType()->isVectorTy()) {
- if (cast<VectorType>(CI->getOperand(0)->getType())
- ->getElementType()
- ->isDoubleTy())
- IntTy = Type::getInt64Ty(*Context);
- if (cast<VectorType>(CI->getOperand(0)->getType())
- ->getElementType()
- ->isHalfTy())
- IntTy = Type::getInt16Ty(*Context);
- RetTy = VectorType::get(IntTy,
- CI->getType()->getVectorNumElements());
- }
- return CI->getCalledFunction()->getName();
- },
- [=](CallInst *NewCI) -> Instruction * {
- Type *RetTy = Type::getInt1Ty(*Context);
- if (NewCI->getType()->isVectorTy())
- RetTy =
- VectorType::get(Type::getInt1Ty(*Context),
- NewCI->getType()->getVectorNumElements());
- return CastInst::CreateTruncOrBitCast(NewCI, RetTy, "",
- NewCI->getNextNode());
- },
- &Attrs)));
-}
-}
-
-bool
-llvm::ReadSPIRV(LLVMContext &C, std::istream &IS, Module *&M,
- std::string &ErrMsg) {
- M = new Module("", C);
- std::unique_ptr<SPIRVModule> BM(SPIRVModule::createSPIRVModule());
-
- IS >> *BM;
-
- SPIRVToLLVM BTL(M, BM.get());
- bool Succeed = true;
- if (!BTL.translate()) {
- BM->getError(ErrMsg);
- Succeed = false;
- }
- llvm::legacy::PassManager PassMgr;
- PassMgr.add(createSPIRVToOCL20());
- PassMgr.add(createOCL20To12());
- PassMgr.run(*M);
-
- if (DbgSaveTmpLLVM)
- dumpLLVM(M, DbgTmpLLVMFileName);
- if (!Succeed) {
- delete M;
- M = nullptr;
- }
- return Succeed;
-}
+ llvm_unreachable("invalid integer size"); + return Prefix + std::string("int") + T->getIntegerBitWidth() + "_t"; + } + } + break; + case OpTypeFloat: + switch(T->getFloatBitWidth()){ + case 16: + return "half"; + case 32: + return "float"; + case 64: + return "double"; + default: + llvm_unreachable("invalid floating pointer bitwidth"); + return std::string("float") + T->getFloatBitWidth() + "_t"; + } + break; + case OpTypeArray: + return "array"; + case OpTypePointer: + return transTypeToOCLTypeName(T->getPointerElementType()) + "*"; + case OpTypeVector: + return transTypeToOCLTypeName(T->getVectorComponentType()) + + T->getVectorComponentCount(); + case OpTypeOpaque: + return T->getName(); + case OpTypeFunction: + llvm_unreachable("Unsupported"); + return "function"; + case OpTypeStruct: { + auto Name = T->getName(); + if (Name.find("struct.") == 0) + Name[6] = ' '; + else if (Name.find("union.") == 0) + Name[5] = ' '; + return Name; + } + case OpTypePipe: + return "pipe"; + case OpTypeSampler: + return "sampler_t"; + case OpTypeImage: { + std::string Name; + Name = rmap<std::string>(static_cast<SPIRVTypeImage *>(T)->getDescriptor()); + if (SPIRVGenImgTypeAccQualPostfix) { + auto ST = static_cast<SPIRVTypeImage *>(T); + insertImageNameAccessQualifier(ST, Name); + } + return Name; + } + default: + if (isOpaqueGenericTypeOpCode(T->getOpCode())) { + return OCLOpaqueTypeOpCodeMap::rmap(T->getOpCode()); + } + llvm_unreachable("Not implemented"); + return "unknown"; + } +} + +std::vector<Type *> +SPIRVToLLVM::transTypeVector(const std::vector<SPIRVType *> &BT) { + std::vector<Type *> T; + for (auto I: BT) + T.push_back(transType(I)); + return T; +} + +std::vector<Value *> +SPIRVToLLVM::transValue(const std::vector<SPIRVValue *> &BV, Function *F, + BasicBlock *BB) { + std::vector<Value *> V; + for (auto I: BV) + V.push_back(transValue(I, F, BB)); + return V; +} + +bool +SPIRVToLLVM::isSPIRVCmpInstTransToLLVMInst(SPIRVInstruction* BI) const { + auto OC = BI->getOpCode(); + return isCmpOpCode(OC) && + !(OC >= OpLessOrGreater && OC <= OpUnordered); +} + +void +SPIRVToLLVM::transFlags(llvm::Value* V) { + if(!isa<Instruction>(V)) + return; + auto OC = cast<Instruction>(V)->getOpcode(); + if (OC == Instruction::AShr || OC == Instruction::LShr) { + cast<BinaryOperator>(V)->setIsExact(); + return; + } +} + +void +SPIRVToLLVM::setName(llvm::Value* V, SPIRVValue* BV) { + auto Name = BV->getName(); + if (!Name.empty() && (!V->hasName() || Name != V->getName())) + V->setName(Name); +} + +void +SPIRVToLLVM::setLLVMLoopMetadata(SPIRVLoopMerge* LM, BranchInst* BI) { + if (!LM) + return; + llvm::MDString *Name = nullptr; + auto Temp = MDNode::getTemporary(*Context, None); + auto Self = MDNode::get(*Context, Temp.get()); + Self->replaceOperandWith(0, Self); + + if (LM->getLoopControl() == LoopControlMaskNone) { + BI->setMetadata("llvm.loop", Self); + return; + } + else if(LM->getLoopControl() == LoopControlUnrollMask) + Name = llvm::MDString::get(*Context, "llvm.loop.unroll.full"); + else if (LM->getLoopControl() == LoopControlDontUnrollMask) + Name = llvm::MDString::get(*Context, "llvm.loop.unroll.disable"); + else + return; + + std::vector<llvm::Metadata *> OpValues(1, Name); + SmallVector<llvm::Metadata *, 2> Metadata; + Metadata.push_back(llvm::MDNode::get(*Context, Self)); + Metadata.push_back(llvm::MDNode::get(*Context, OpValues)); + + llvm::MDNode *Node = llvm::MDNode::get(*Context, Metadata); + Node->replaceOperandWith(0, Node); + BI->setMetadata("llvm.loop", Node); +} + +void SPIRVToLLVM::insertImageNameAccessQualifier(SPIRV::SPIRVTypeImage* ST, std::string &Name) { + std::string QName = rmap<std::string>(ST->getAccessQualifier()); + // transform: read_only -> ro, write_only -> wo, read_write -> rw + QName = QName.substr(0,1) + QName.substr(QName.find("_") + 1, 1) + "_"; + assert(!Name.empty() && "image name should not be empty"); + Name.insert(Name.size() - 1, QName); +} + +Value * +SPIRVToLLVM::transValue(SPIRVValue *BV, Function *F, BasicBlock *BB, + bool CreatePlaceHolder){ + SPIRVToLLVMValueMap::iterator Loc = ValueMap.find(BV); + if (Loc != ValueMap.end() && (!PlaceholderMap.count(BV) || CreatePlaceHolder)) + return Loc->second; + + SPIRVDBG(spvdbgs() << "[transValue] " << *BV << " -> ";) + BV->validate(); + + auto V = transValueWithoutDecoration(BV, F, BB, CreatePlaceHolder); + if (!V) { + SPIRVDBG(dbgs() << " Warning ! nullptr\n";) + return nullptr; + } + setName(V, BV); + if (!transDecoration(BV, V)) { + assert (0 && "trans decoration fail"); + return nullptr; + } + transFlags(V); + + SPIRVDBG(dbgs() << *V << '\n';) + + return V; +} + +Value * +SPIRVToLLVM::transDeviceEvent(SPIRVValue *BV, Function *F, BasicBlock *BB) { + auto Val = transValue(BV, F, BB, false); + auto Ty = dyn_cast<PointerType>(Val->getType()); + assert(Ty && "Invalid Device Event"); + if (Ty->getAddressSpace() == SPIRAS_Generic) + return Val; + + IRBuilder<> Builder(BB); + auto EventTy = PointerType::get(Ty->getElementType(), SPIRAS_Generic); + return Builder.CreateAddrSpaceCast(Val, EventTy); +} + +Value * +SPIRVToLLVM::transConvertInst(SPIRVValue* BV, Function* F, BasicBlock* BB) { + SPIRVUnary* BC = static_cast<SPIRVUnary*>(BV); + auto Src = transValue(BC->getOperand(0), F, BB, BB ? true : false); + auto Dst = transType(BC->getType()); + CastInst::CastOps CO = Instruction::BitCast; + bool IsExt = Dst->getScalarSizeInBits() + > Src->getType()->getScalarSizeInBits(); + switch (BC->getOpCode()) { + case OpPtrCastToGeneric: + case OpGenericCastToPtr: + CO = Instruction::AddrSpaceCast; + break; + case OpSConvert: + CO = IsExt ? Instruction::SExt : Instruction::Trunc; + break; + case OpUConvert: + CO = IsExt ? Instruction::ZExt : Instruction::Trunc; + break; + case OpFConvert: + CO = IsExt ? Instruction::FPExt : Instruction::FPTrunc; + break; + default: + CO = static_cast<CastInst::CastOps>(OpCodeMap::rmap(BC->getOpCode())); + } + assert(CastInst::isCast(CO) && "Invalid cast op code"); + SPIRVDBG(if (!CastInst::castIsValid(CO, Src, Dst)) { + spvdbgs() << "Invalid cast: " << *BV << " -> "; + dbgs() << "Op = " << CO << ", Src = " << *Src << " Dst = " << *Dst << '\n'; + }) + if (BB) + return CastInst::Create(CO, Src, Dst, BV->getName(), BB); + return ConstantExpr::getCast(CO, dyn_cast<Constant>(Src), Dst); +} + +BinaryOperator *SPIRVToLLVM::transShiftLogicalBitwiseInst(SPIRVValue* BV, + BasicBlock* BB,Function* F) { + SPIRVBinary* BBN = static_cast<SPIRVBinary*>(BV); + assert(BB && "Invalid BB"); + Instruction::BinaryOps BO; + auto OP = BBN->getOpCode(); + if (isLogicalOpCode(OP)) + OP = IntBoolOpMap::rmap(OP); + BO = static_cast<Instruction::BinaryOps>(OpCodeMap::rmap(OP)); + auto Inst = BinaryOperator::Create(BO, + transValue(BBN->getOperand(0), F, BB), + transValue(BBN->getOperand(1), F, BB), BV->getName(), BB); + return Inst; +} + +Instruction * +SPIRVToLLVM::transCmpInst(SPIRVValue* BV, BasicBlock* BB, Function* F) { + SPIRVCompare* BC = static_cast<SPIRVCompare*>(BV); + assert(BB && "Invalid BB"); + SPIRVType* BT = BC->getOperand(0)->getType(); + Instruction* Inst = nullptr; + auto OP = BC->getOpCode(); + if (isLogicalOpCode(OP)) + OP = IntBoolOpMap::rmap(OP); + if (BT->isTypeVectorOrScalarInt() || BT->isTypeVectorOrScalarBool() || + BT->isTypePointer()) + Inst = new ICmpInst(*BB, CmpMap::rmap(OP), + transValue(BC->getOperand(0), F, BB), + transValue(BC->getOperand(1), F, BB)); + else if (BT->isTypeVectorOrScalarFloat()) + Inst = new FCmpInst(*BB, CmpMap::rmap(OP), + transValue(BC->getOperand(0), F, BB), + transValue(BC->getOperand(1), F, BB)); + assert(Inst && "not implemented"); + return Inst; +} + +bool +SPIRVToLLVM::postProcessOCL() { + std::string DemangledName; + SPIRVWord SrcLangVer = 0; + BM->getSourceLanguage(&SrcLangVer); + bool isCPP = SrcLangVer == kOCLVer::CL21; + for (auto I = M->begin(), E = M->end(); I != E;) { + auto F = I++; + if (F->hasName() && F->isDeclaration()) { + DEBUG(dbgs() << "[postProcessOCL sret] " << *F << '\n'); + if (F->getReturnType()->isStructTy() && + oclIsBuiltin(F->getName(), &DemangledName, isCPP)) { + if (!postProcessOCLBuiltinReturnStruct(&(*F))) + return false; + } + } + } + for (auto I = M->begin(), E = M->end(); I != E;) { + auto F = I++; + if (F->hasName() && F->isDeclaration()) { + DEBUG(dbgs() << "[postProcessOCL array arg] " << *F << '\n'); + if (hasArrayArg(&(*F)) && oclIsBuiltin(F->getName(), &DemangledName, isCPP)) + if (!postProcessOCLBuiltinWithArrayArguments(&(*F), DemangledName)) + return false; + } + } + return true; +} + +bool +SPIRVToLLVM::postProcessOCLBuiltinReturnStruct(Function *F) { + std::string Name = F->getName(); + F->setName(Name + ".old"); + for (auto I = F->user_begin(), E = F->user_end(); I != E;) { + if (auto CI = dyn_cast<CallInst>(*I++)) { + auto ST = dyn_cast<StoreInst>(*(CI->user_begin())); + assert(ST); + std::vector<Type *> ArgTys; + getFunctionTypeParameterTypes(F->getFunctionType(), ArgTys); + ArgTys.insert(ArgTys.begin(), PointerType::get(F->getReturnType(), + SPIRAS_Private)); + auto newF = getOrCreateFunction(M, Type::getVoidTy(*Context), + ArgTys, Name); + newF->setCallingConv(F->getCallingConv()); + auto Args = getArguments(CI); + Args.insert(Args.begin(), ST->getPointerOperand()); + auto NewCI = CallInst::Create(newF, Args, CI->getName(), CI); + NewCI->setCallingConv(CI->getCallingConv()); + ST->eraseFromParent(); + CI->eraseFromParent(); + } + } + F->eraseFromParent(); + return true; +} + +bool +SPIRVToLLVM::postProcessOCLBuiltinWithArrayArguments(Function* F, + const std::string &DemangledName) { + DEBUG(dbgs() << "[postProcessOCLBuiltinWithArrayArguments] " << *F << '\n'); + auto Attrs = F->getAttributes(); + auto Name = F->getName(); + mutateFunction(F, [=](CallInst *CI, std::vector<Value *> &Args) { + auto FBegin = CI->getParent()->getParent()->begin()->getFirstInsertionPt(); + for (auto &I:Args) { + auto T = I->getType(); + if (!T->isArrayTy()) + continue; + auto Alloca = new AllocaInst(T, 0, "", &(*FBegin)); + new StoreInst(I, Alloca, false, CI); + auto Zero = ConstantInt::getNullValue(Type::getInt32Ty(T->getContext())); + Value *Index[] = {Zero, Zero}; + I = GetElementPtrInst::CreateInBounds(Alloca, Index, "", CI); + } + return Name; + }, nullptr, &Attrs); + return true; +} + +// ToDo: Handle unsigned integer return type. May need spec change. +Instruction * +SPIRVToLLVM::postProcessOCLReadImage(SPIRVInstruction *BI, CallInst* CI, + const std::string &FuncName) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + StringRef ImageTypeName; + bool isDepthImage = false; + if (isOCLImageType( + (cast<CallInst>(CI->getOperand(0)))->getArgOperand(0)->getType(), + &ImageTypeName)) + isDepthImage = ImageTypeName.endswith("depth_t"); + return mutateCallInstOCL( + M, CI, + [=](CallInst *, std::vector<Value *> &Args, llvm::Type *&RetTy) { + CallInst *CallSampledImg = cast<CallInst>(Args[0]); + auto Img = CallSampledImg->getArgOperand(0); + assert(isOCLImageType(Img->getType())); + auto Sampler = CallSampledImg->getArgOperand(1); + Args[0] = Img; + Args.insert(Args.begin() + 1, Sampler); + if(Args.size() > 4 ) { + ConstantInt* ImOp = dyn_cast<ConstantInt>(Args[3]); + ConstantFP* LodVal = dyn_cast<ConstantFP>(Args[4]); + // Drop "Image Operands" argument. + Args.erase(Args.begin() + 3, Args.begin() + 4); + // If the image operand is LOD and its value is zero, drop it too. + if (ImOp && LodVal && LodVal->isNullValue() && + ImOp->getZExtValue() == ImageOperandsMask::ImageOperandsLodMask ) + Args.erase(Args.begin() + 3, Args.end()); + } + if (CallSampledImg->hasOneUse()) { + CallSampledImg->replaceAllUsesWith( + UndefValue::get(CallSampledImg->getType())); + CallSampledImg->dropAllReferences(); + CallSampledImg->eraseFromParent(); + } + Type *T = CI->getType(); + if (auto VT = dyn_cast<VectorType>(T)) + T = VT->getElementType(); + RetTy = isDepthImage ? T : CI->getType(); + return std::string(kOCLBuiltinName::SampledReadImage) + + (T->isFloatingPointTy() ? 'f' : 'i'); + }, + [=](CallInst *NewCI) -> Instruction * { + if (isDepthImage) + return InsertElementInst::Create( + UndefValue::get(VectorType::get(NewCI->getType(), 4)), NewCI, + getSizet(M, 0), "", NewCI->getParent()); + return NewCI; + }, + &Attrs); +} + +CallInst* +SPIRVToLLVM::postProcessOCLWriteImage(SPIRVInstruction *BI, CallInst *CI, + const std::string &DemangledName) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + return mutateCallInstOCL(M, CI, [=](CallInst *, std::vector<Value *> &Args) { + llvm::Type *T = Args[2]->getType(); + if (Args.size() > 4) { + ConstantInt* ImOp = dyn_cast<ConstantInt>(Args[3]); + ConstantFP* LodVal = dyn_cast<ConstantFP>(Args[4]); + // Drop "Image Operands" argument. + Args.erase(Args.begin() + 3, Args.begin() + 4); + // If the image operand is LOD and its value is zero, drop it too. + if (ImOp && LodVal && LodVal->isNullValue() && + ImOp->getZExtValue() == ImageOperandsMask::ImageOperandsLodMask ) + Args.erase(Args.begin() + 3, Args.end()); + else + std::swap(Args[2], Args[3]); + } + return std::string(kOCLBuiltinName::WriteImage) + + (T->isFPOrFPVectorTy() ? 'f' : 'i'); + }, &Attrs); +} + +CallInst * +SPIRVToLLVM::postProcessOCLBuildNDRange(SPIRVInstruction *BI, CallInst *CI, + const std::string &FuncName) { + assert(CI->getNumArgOperands() == 3); + auto GWS = CI->getArgOperand(0); + auto LWS = CI->getArgOperand(1); + auto GWO = CI->getArgOperand(2); + CI->setArgOperand(0, GWO); + CI->setArgOperand(1, GWS); + CI->setArgOperand(2, LWS); + return CI; +} + +Instruction * +SPIRVToLLVM::postProcessGroupAllAny(CallInst *CI, + const std::string &DemangledName) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + return mutateCallInstSPIRV( + M, CI, + [=](CallInst *, std::vector<Value *> &Args, llvm::Type *&RetTy) { + Type *Int32Ty = Type::getInt32Ty(*Context); + RetTy = Int32Ty; + Args[1] = CastInst::CreateZExtOrBitCast(Args[1], Int32Ty, "", CI); + return DemangledName; + }, + [=](CallInst *NewCI) -> Instruction * { + Type *RetTy = Type::getInt1Ty(*Context); + return CastInst::CreateTruncOrBitCast(NewCI, RetTy, "", + NewCI->getNextNode()); + }, + &Attrs); +} + +CallInst * +SPIRVToLLVM::expandOCLBuiltinWithScalarArg(CallInst* CI, + const std::string &FuncName) { + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + if (!CI->getOperand(0)->getType()->isVectorTy() && + CI->getOperand(1)->getType()->isVectorTy()) { + return mutateCallInstOCL(M, CI, [=](CallInst *, std::vector<Value *> &Args){ + unsigned vecSize = CI->getOperand(1)->getType()->getVectorNumElements(); + Value *NewVec = nullptr; + if (auto CA = dyn_cast<Constant>(Args[0])) + NewVec = ConstantVector::getSplat(vecSize, CA); + else { + NewVec = ConstantVector::getSplat(vecSize, + Constant::getNullValue(Args[0]->getType())); + NewVec = InsertElementInst::Create(NewVec, Args[0], getInt32(M, 0), "", + CI); + NewVec = new ShuffleVectorInst(NewVec, NewVec, + ConstantVector::getSplat(vecSize, getInt32(M, 0)), "", CI); + } + NewVec->takeName(Args[0]); + Args[0] = NewVec; + return FuncName; + }, &Attrs); + } + return CI; +} + +std::string +SPIRVToLLVM::transOCLPipeTypeAccessQualifier(SPIRV::SPIRVTypePipe* ST) { + return SPIRSPIRVAccessQualifierMap::rmap(ST->getAccessQualifier()); +} + +void +SPIRVToLLVM::transGeneratorMD() { + SPIRVMDBuilder B(*M); + B.addNamedMD(kSPIRVMD::Generator) + .addOp() + .addU16(BM->getGeneratorId()) + .addU16(BM->getGeneratorVer()) + .done(); +} + +Value * +SPIRVToLLVM::oclTransConstantSampler(SPIRV::SPIRVConstantSampler* BCS) { + auto Lit = (BCS->getAddrMode() << 1) | + BCS->getNormalized() | + ((BCS->getFilterMode() + 1) << 4); + auto Ty = IntegerType::getInt32Ty(*Context); + return ConstantInt::get(Ty, Lit); +} + +Value * +SPIRVToLLVM::oclTransConstantPipeStorage( + SPIRV::SPIRVConstantPipeStorage* BCPS) { + + string CPSName = string(kSPIRVTypeName::PrefixAndDelim) + + kSPIRVTypeName::ConstantPipeStorage; + + auto Int32Ty = IntegerType::getInt32Ty(*Context); + auto CPSTy = M->getTypeByName(CPSName); + if (!CPSTy) { + Type* CPSElemsTy[] = { Int32Ty, Int32Ty, Int32Ty }; + CPSTy = StructType::create(*Context, CPSElemsTy, CPSName); + } + + assert(CPSTy != nullptr && "Could not create spirv.ConstantPipeStorage"); + + Constant* CPSElems[] = { + ConstantInt::get(Int32Ty, BCPS->getPacketSize()), + ConstantInt::get(Int32Ty, BCPS->getPacketAlign()), + ConstantInt::get(Int32Ty, BCPS->getCapacity()) + }; + + return new GlobalVariable(*M, CPSTy, false, GlobalValue::LinkOnceODRLinkage, + ConstantStruct::get(CPSTy, CPSElems), BCPS->getName(), + nullptr, GlobalValue::NotThreadLocal, SPIRAS_Global); +} + +/// For instructions, this function assumes they are created in order +/// and appended to the given basic block. An instruction may use a +/// instruction from another BB which has not been translated. Such +/// instructions should be translated to place holders at the point +/// of first use, then replaced by real instructions when they are +/// created. +/// +/// When CreatePlaceHolder is true, create a load instruction of a +/// global variable as placeholder for SPIRV instruction. Otherwise, +/// create instruction and replace placeholder if there is one. +Value * +SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F, + BasicBlock *BB, bool CreatePlaceHolder){ + + auto OC = BV->getOpCode(); + IntBoolOpMap::rfind(OC, &OC); + + // Translation of non-instruction values + switch(OC) { + case OpConstant: { + SPIRVConstant *BConst = static_cast<SPIRVConstant *>(BV); + SPIRVType *BT = BV->getType(); + Type *LT = transType(BT); + switch(BT->getOpCode()) { + case OpTypeBool: + case OpTypeInt: + return mapValue(BV, ConstantInt::get(LT, BConst->getZExtIntValue(), + static_cast<SPIRVTypeInt*>(BT)->isSigned())); + case OpTypeFloat: { + const llvm::fltSemantics *FS = nullptr; + switch (BT->getFloatBitWidth()) { + case 16: + FS = &APFloat::IEEEhalf(); + break; + case 32: + FS = &APFloat::IEEEsingle(); + break; + case 64: + FS = &APFloat::IEEEdouble(); + break; + default: + llvm_unreachable("invalid float type"); + } + return mapValue(BV, ConstantFP::get(*Context, APFloat(*FS, + APInt(BT->getFloatBitWidth(), BConst->getZExtIntValue())))); + } + default: + llvm_unreachable("Not implemented"); + return nullptr; + } + } + + case OpConstantTrue: + return mapValue(BV, ConstantInt::getTrue(*Context)); + + case OpConstantFalse: + return mapValue(BV, ConstantInt::getFalse(*Context)); + + case OpConstantNull: { + auto LT = transType(BV->getType()); + return mapValue(BV, Constant::getNullValue(LT)); + } + + case OpConstantComposite: { + auto BCC = static_cast<SPIRVConstantComposite*>(BV); + std::vector<Constant *> CV; + for (auto &I:BCC->getElements()) + CV.push_back(dyn_cast<Constant>(transValue(I, F, BB))); + switch(BV->getType()->getOpCode()) { + case OpTypeVector: + return mapValue(BV, ConstantVector::get(CV)); + case OpTypeArray: + return mapValue(BV, ConstantArray::get( + dyn_cast<ArrayType>(transType(BCC->getType())), CV)); + case OpTypeStruct: { + auto BCCTy = dyn_cast<StructType>(transType(BCC->getType())); + auto Members = BCCTy->getNumElements(); + auto Constants = CV.size(); + //if we try to initialize constant TypeStruct, add bitcasts + //if src and dst types are both pointers but to different types + if (Members == Constants) { + for (unsigned i = 0; i < Members; ++i) { + if (CV[i]->getType() == BCCTy->getElementType(i)) + continue; + if (!CV[i]->getType()->isPointerTy() || + !BCCTy->getElementType(i)->isPointerTy()) + continue; + + CV[i] = ConstantExpr::getBitCast(CV[i], BCCTy->getElementType(i)); + } + } + + return mapValue(BV, ConstantStruct::get( + dyn_cast<StructType>(transType(BCC->getType())), CV)); + } + default: + llvm_unreachable("not implemented"); + return nullptr; + } + } + + case OpConstantSampler: { + auto BCS = static_cast<SPIRVConstantSampler*>(BV); + return mapValue(BV, oclTransConstantSampler(BCS)); + } + + case OpConstantPipeStorage: { + auto BCPS = static_cast<SPIRVConstantPipeStorage*>(BV); + return mapValue(BV, oclTransConstantPipeStorage(BCPS)); + } + + case OpSpecConstantOp: { + auto BI = createInstFromSpecConstantOp( + static_cast<SPIRVSpecConstantOp*>(BV)); + return mapValue(BV, transValue(BI, nullptr, nullptr, false)); + } + + case OpUndef: + return mapValue(BV, UndefValue::get(transType(BV->getType()))); + + case OpVariable: { + auto BVar = static_cast<SPIRVVariable *>(BV); + auto Ty = transType(BVar->getType()->getPointerElementType()); + bool IsConst = BVar->isConstant(); + llvm::GlobalValue::LinkageTypes LinkageTy = transLinkageType(BVar); + Constant *Initializer = nullptr; + SPIRVValue *Init = BVar->getInitializer(); + if (Init) + Initializer = dyn_cast<Constant>(transValue(Init, F, BB, false)); + else if (LinkageTy == GlobalValue::CommonLinkage) + // In LLVM variables with common linkage type must be initilized by 0 + Initializer = Constant::getNullValue(Ty); + else if (BVar->getStorageClass() == SPIRVStorageClassKind::StorageClassWorkgroup) + Initializer = dyn_cast<Constant>(UndefValue::get(Ty)); + + SPIRVStorageClassKind BS = BVar->getStorageClass(); + if (BS == StorageClassFunction && !Init) { + assert (BB && "Invalid BB"); + return mapValue(BV, new AllocaInst(Ty, 0, BV->getName(), BB)); + } + auto AddrSpace = SPIRSPIRVAddrSpaceMap::rmap(BS); + auto LVar = new GlobalVariable(*M, Ty, IsConst, LinkageTy, Initializer, + BV->getName(), 0, GlobalVariable::NotThreadLocal, AddrSpace); + LVar->setUnnamedAddr((IsConst && Ty->isArrayTy() && + Ty->getArrayElementType()->isIntegerTy(8)) + ? GlobalValue::UnnamedAddr::Global + : GlobalValue::UnnamedAddr::None); + SPIRVBuiltinVariableKind BVKind; + if (BVar->isBuiltin(&BVKind)) + BuiltinGVMap[LVar] = BVKind; + return mapValue(BV, LVar); + } + + case OpFunctionParameter: { + auto BA = static_cast<SPIRVFunctionParameter*>(BV); + assert (F && "Invalid function"); + unsigned ArgNo = 0; + for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; + ++I, ++ArgNo) { + if (ArgNo == BA->getArgNo()) + return mapValue(BV, &(*I)); + } + llvm_unreachable("Invalid argument"); + return nullptr; + } + + case OpFunction: + return mapValue(BV, transFunction(static_cast<SPIRVFunction *>(BV))); + + case OpLabel: + return mapValue(BV, BasicBlock::Create(*Context, BV->getName(), F)); + + default: + // do nothing + break; + } + + // During translation of OpSpecConstantOp we create an instruction + // corresponding to the Opcode operand and then translate this instruction. + // For such instruction BB and F should be nullptr, because it is a constant + // expression declared out of scope of any basic block or function. + // All other values require valid BB pointer. + assert(((isSpecConstantOpAllowedOp(OC) && !F && !BB) || BB) && "Invalid BB"); + + // Creation of place holder + if (CreatePlaceHolder) { + auto GV = new GlobalVariable(*M, + transType(BV->getType()), + false, + GlobalValue::PrivateLinkage, + nullptr, + std::string(kPlaceholderPrefix) + BV->getName(), + 0, GlobalVariable::NotThreadLocal, 0); + auto LD = new LoadInst(GV, BV->getName(), BB); + PlaceholderMap[BV] = LD; + return mapValue(BV, LD); + } + + // Translation of instructions + switch (BV->getOpCode()) { + case OpBranch: { + auto BR = static_cast<SPIRVBranch *>(BV); + auto BI = BranchInst::Create( + dyn_cast<BasicBlock>(transValue(BR->getTargetLabel(), F, BB)), BB); + if (auto LM = static_cast<SPIRVLoopMerge *>(BR->getPrevious())) + setLLVMLoopMetadata(LM, BI); + return mapValue(BV, BI); + } + + case OpBranchConditional: { + auto BR = static_cast<SPIRVBranchConditional *>(BV); + auto BC = BranchInst::Create( + dyn_cast<BasicBlock>(transValue(BR->getTrueLabel(), F, BB)), + dyn_cast<BasicBlock>(transValue(BR->getFalseLabel(), F, BB)), + transValue(BR->getCondition(), F, BB), BB); + if (auto LM = static_cast<SPIRVLoopMerge *>(BR->getPrevious())) + setLLVMLoopMetadata(LM, BC); + return mapValue(BV, BC); + } + + case OpPhi: { + auto Phi = static_cast<SPIRVPhi *>(BV); + auto LPhi = dyn_cast<PHINode>(mapValue( + BV, PHINode::Create(transType(Phi->getType()), + Phi->getPairs().size() / 2, Phi->getName(), BB))); + Phi->foreachPair([&](SPIRVValue *IncomingV, SPIRVBasicBlock *IncomingBB, + size_t Index) { + auto Translated = transValue(IncomingV, F, BB); + LPhi->addIncoming(Translated, + dyn_cast<BasicBlock>(transValue(IncomingBB, F, BB))); + }); + return LPhi; + } + + case OpUnreachable: + return mapValue(BV, new UnreachableInst(*Context, BB)); + + case OpReturn: + return mapValue(BV, ReturnInst::Create(*Context, BB)); + + case OpReturnValue: { + auto RV = static_cast<SPIRVReturnValue *>(BV); + return mapValue( + BV, ReturnInst::Create(*Context, + transValue(RV->getReturnValue(), F, BB), BB)); + } + + case OpLifetimeStart: { + SPIRVLifetimeStart *LTStart = static_cast<SPIRVLifetimeStart*>(BV); + IRBuilder<> Builder(BB); + SPIRVWord Size = LTStart->getSize(); + ConstantInt *S = nullptr; + if (Size) + S = Builder.getInt64(Size); + Value* Var = transValue(LTStart->getObject(), F, BB); + CallInst *Start = Builder.CreateLifetimeStart(Var, S); + return mapValue(BV, Start->getOperand(1)); + } + + case OpLifetimeStop: { + SPIRVLifetimeStop *LTStop = static_cast<SPIRVLifetimeStop*>(BV); + IRBuilder<> Builder(BB); + SPIRVWord Size = LTStop->getSize(); + ConstantInt *S = nullptr; + if (Size) + S = Builder.getInt64(Size); + auto Var = transValue(LTStop->getObject(), F, BB); + for (const auto &I : Var->users()) + if (auto II = getLifetimeStartIntrinsic(dyn_cast<Instruction>(I))) + return mapValue(BV, Builder.CreateLifetimeEnd(II->getOperand(1), S)); + return mapValue(BV, Builder.CreateLifetimeEnd(Var, S)); + } + + case OpStore: { + SPIRVStore *BS = static_cast<SPIRVStore*>(BV); + StoreInst *SI = new StoreInst(transValue(BS->getSrc(), F, BB), + transValue(BS->getDst(), F, BB), + BS->SPIRVMemoryAccess::isVolatile(), + BS->SPIRVMemoryAccess::getAlignment(), BB); + if (BS->SPIRVMemoryAccess::isNonTemporal()) + transNonTemporalMetadata(SI); + return mapValue(BV, SI); + } + + case OpLoad: { + SPIRVLoad *BL = static_cast<SPIRVLoad*>(BV); + LoadInst *LI = new LoadInst(transValue(BL->getSrc(), F, BB), BV->getName(), + BL->SPIRVMemoryAccess::isVolatile(), + BL->SPIRVMemoryAccess::getAlignment(), BB); + if (BL->SPIRVMemoryAccess::isNonTemporal()) + transNonTemporalMetadata(LI); + return mapValue(BV, LI); + } + + case OpCopyMemorySized: { + SPIRVCopyMemorySized *BC = static_cast<SPIRVCopyMemorySized *>(BV); + CallInst *CI = nullptr; + llvm::Value *Dst = transValue(BC->getTarget(), F, BB); + unsigned Align = BC->getAlignment(); + llvm::Value *Size = transValue(BC->getSize(), F, BB); + bool isVolatile = BC->SPIRVMemoryAccess::isVolatile(); + IRBuilder<> Builder(BB); + + // If we copy from zero-initialized array, we can optimize it to llvm.memset + if (BC->getSource()->getOpCode() == OpBitcast) { + SPIRVValue *Source = + static_cast<SPIRVBitcast*>(BC->getSource())->getOperand(0); + if (Source->isVariable()) { + auto *Init = static_cast<SPIRVVariable*>(Source)->getInitializer(); + if (isa<OpConstantNull>(Init)) { + SPIRVType *Ty = static_cast<SPIRVConstantNull*>(Init)->getType(); + if (isa<OpTypeArray>(Ty)) { + SPIRVTypeArray *AT = static_cast<SPIRVTypeArray*>(Ty); + Type *SrcTy = transType(AT->getArrayElementType()); + assert(SrcTy->isIntegerTy(8)); + llvm::Value *Src = ConstantInt::get(SrcTy, 0); + CI = Builder.CreateMemSet(Dst, Src, Size, Align, isVolatile); + } + } + } + } + if (!CI) { + llvm::Value *Src = transValue(BC->getSource(), F, BB); + CI = Builder.CreateMemCpy(Dst, Align, Src, Align, Size, isVolatile); + } + if (isFuncNoUnwind()) + CI->getFunction()->addFnAttr(Attribute::NoUnwind); + return mapValue(BV, CI); + } + + case OpSelect: { + SPIRVSelect *BS = static_cast<SPIRVSelect*>(BV); + return mapValue(BV, + SelectInst::Create(transValue(BS->getCondition(), F, BB), + transValue(BS->getTrueValue(), F, BB), + transValue(BS->getFalseValue(), F, BB), + BV->getName(), BB)); + } + + case OpLine: + case OpSelectionMerge: // OpenCL Compiler does not use this instruction + case OpLoopMerge: // Should be translated at OpBranch or OpBranchConditional cases + return nullptr; + + case OpSwitch: { + auto BS = static_cast<SPIRVSwitch *>(BV); + auto Select = transValue(BS->getSelect(), F, BB); + auto LS = SwitchInst::Create( + Select, dyn_cast<BasicBlock>(transValue(BS->getDefault(), F, BB)), + BS->getNumPairs(), BB); + BS->foreachPair( + [&](SPIRVSwitch::LiteralTy Literals, SPIRVBasicBlock *Label) { + assert(!Literals.empty() && "Literals should not be empty"); + assert(Literals.size() <= 2 && "Number of literals should not be more then two"); + uint64_t Literal = uint64_t(Literals.at(0)); + if (Literals.size() == 2) { + Literal += uint64_t(Literals.at(1)) << 32; + } + LS->addCase(ConstantInt::get(dyn_cast<IntegerType>(Select->getType()), Literal), + dyn_cast<BasicBlock>(transValue(Label, F, BB))); + }); + return mapValue(BV, LS); + } + + case OpVectorTimesScalar: { + auto VTS = static_cast<SPIRVVectorTimesScalar*>(BV); + IRBuilder<> Builder(BB); + auto Scalar = transValue(VTS->getScalar(), F, BB); + auto Vector = transValue(VTS->getVector(), F, BB); + assert(Vector->getType()->isVectorTy() && "Invalid type"); + unsigned vecSize = Vector->getType()->getVectorNumElements(); + auto NewVec = Builder.CreateVectorSplat(vecSize, Scalar, Scalar->getName()); + NewVec->takeName(Scalar); + auto Scale = Builder.CreateFMul(Vector, NewVec, "scale"); + return mapValue(BV, Scale); + } + + case OpCopyObject: { + SPIRVCopyObject *CO = static_cast<SPIRVCopyObject *>(BV); + AllocaInst* AI = new AllocaInst(transType(CO->getOperand()->getType()), 0, "", BB); + new StoreInst(transValue(CO->getOperand(), F, BB), AI, BB); + LoadInst* LI = new LoadInst(AI, "", BB); + return mapValue(BV, LI); + } + + case OpAccessChain: + case OpInBoundsAccessChain: + case OpPtrAccessChain: + case OpInBoundsPtrAccessChain: { + auto AC = static_cast<SPIRVAccessChainBase *>(BV); + auto Base = transValue(AC->getBase(), F, BB); + auto Index = transValue(AC->getIndices(), F, BB); + if (!AC->hasPtrIndex()) + Index.insert(Index.begin(), getInt32(M, 0)); + auto IsInbound = AC->isInBounds(); + Value *V = nullptr; + if (BB) { + auto GEP = GetElementPtrInst::Create(nullptr, Base, Index, BV->getName(), BB); + GEP->setIsInBounds(IsInbound); + V = GEP; + } else { + V = ConstantExpr::getGetElementPtr(nullptr, dyn_cast<Constant>(Base), Index, + IsInbound); + } + return mapValue(BV, V); + } + + case OpCompositeConstruct: { + auto CC = static_cast<SPIRVCompositeConstruct *>(BV); + auto Constituents = transValue(CC->getConstituents(), F, BB); + std::vector<Constant*> CV; + for (const auto &I : Constituents) { + CV.push_back(dyn_cast<Constant>(I)); + } + switch (BV->getType()->getOpCode()) { + case OpTypeVector: + return mapValue(BV, ConstantVector::get(CV)); + case OpTypeArray: + return mapValue(BV, ConstantArray::get( + dyn_cast<ArrayType>(transType(CC->getType())), CV)); + case OpTypeStruct: + return mapValue(BV, ConstantStruct::get( + dyn_cast<StructType>(transType(CC->getType())), CV)); + default: + llvm_unreachable("Unhandled type!"); + } + } + + case OpCompositeExtract: { + SPIRVCompositeExtract *CE = static_cast<SPIRVCompositeExtract *>(BV); + if (CE->getComposite()->getType()->isTypeVector()) { + assert(CE->getIndices().size() == 1 && "Invalid index"); + return mapValue( + BV, ExtractElementInst::Create( + transValue(CE->getComposite(), F, BB), + ConstantInt::get(*Context, APInt(32, CE->getIndices()[0])), + BV->getName(), BB)); + } + return mapValue( + BV, ExtractValueInst::Create( + transValue(CE->getComposite(), F, BB), + CE->getIndices(), BV->getName(), BB)); + } + + case OpVectorExtractDynamic: { + auto CE = static_cast<SPIRVVectorExtractDynamic *>(BV); + return mapValue( + BV, ExtractElementInst::Create(transValue(CE->getVector(), F, BB), + transValue(CE->getIndex(), F, BB), + BV->getName(), BB)); + } + + case OpCompositeInsert: { + auto CI = static_cast<SPIRVCompositeInsert *>(BV); + if (CI->getComposite()->getType()->isTypeVector()) { + assert(CI->getIndices().size() == 1 && "Invalid index"); + return mapValue( + BV, InsertElementInst::Create( + transValue(CI->getComposite(), F, BB), + transValue(CI->getObject(), F, BB), + ConstantInt::get(*Context, APInt(32, CI->getIndices()[0])), + BV->getName(), BB)); + } + return mapValue( + BV, InsertValueInst::Create( + transValue(CI->getComposite(), F, BB), + transValue(CI->getObject(), F, BB), + CI->getIndices(), BV->getName(), BB)); + } + + case OpVectorInsertDynamic: { + auto CI = static_cast<SPIRVVectorInsertDynamic *>(BV); + return mapValue( + BV, InsertElementInst::Create(transValue(CI->getVector(), F, BB), + transValue(CI->getComponent(), F, BB), + transValue(CI->getIndex(), F, BB), + BV->getName(), BB)); + } + + case OpVectorShuffle: { + auto VS = static_cast<SPIRVVectorShuffle *>(BV); + std::vector<Constant *> Components; + IntegerType *Int32Ty = IntegerType::get(*Context, 32); + for (auto I : VS->getComponents()) { + if (I == static_cast<SPIRVWord>(-1)) + Components.push_back(UndefValue::get(Int32Ty)); + else + Components.push_back(ConstantInt::get(Int32Ty, I)); + } + return mapValue(BV, + new ShuffleVectorInst(transValue(VS->getVector1(), F, BB), + transValue(VS->getVector2(), F, BB), + ConstantVector::get(Components), + BV->getName(), BB)); + } + + case OpFunctionCall: { + SPIRVFunctionCall *BC = static_cast<SPIRVFunctionCall *>(BV); + auto Call = CallInst::Create(transFunction(BC->getFunction()), + transValue(BC->getArgumentValues(), F, BB), + BC->getName(), BB); + setCallingConv(Call); + setAttrByCalledFunc(Call); + return mapValue(BV, Call); + } + + case OpExtInst: + return mapValue( + BV, transOCLBuiltinFromExtInst(static_cast<SPIRVExtInst *>(BV), BB)); + + case OpControlBarrier: + case OpMemoryBarrier: + return mapValue( + BV, transOCLBarrierFence(static_cast<SPIRVInstruction *>(BV), BB)); + + case OpSNegate: { + SPIRVUnary *BC = static_cast<SPIRVUnary *>(BV); + return mapValue( + BV, BinaryOperator::CreateNSWNeg(transValue(BC->getOperand(0), F, BB), + BV->getName(), BB)); + } + + case OpFMod: { + // translate OpFMod(a, b) to copysign(frem(a, b), b) + SPIRVFMod *FMod = static_cast<SPIRVFMod *>(BV); + auto Dividend = transValue(FMod->getDividend(), F, BB); + auto Divisor = transValue(FMod->getDivisor(), F, BB); + auto FRem = BinaryOperator::CreateFRem(Dividend, Divisor, "frem.res", BB); + + std::string UnmangledName = OCLExtOpMap::map(OpenCLLIB::Copysign); + std::string MangledName = "copysign"; + + std::vector<Type *> ArgTypes; + ArgTypes.push_back(FRem->getType()); + ArgTypes.push_back(Divisor->getType()); + MangleOpenCLBuiltin(UnmangledName, ArgTypes, MangledName); + + auto FT = FunctionType::get(transType(BV->getType()), ArgTypes, false); + auto Func = Function::Create(FT, GlobalValue::ExternalLinkage, MangledName, M); + Func->setCallingConv(CallingConv::SPIR_FUNC); + if (isFuncNoUnwind()) + Func->addFnAttr(Attribute::NoUnwind); + + std::vector<Value *> Args; + Args.push_back(FRem); + Args.push_back(Divisor); + + auto Call = CallInst::Create(Func, Args, "copysign", BB); + setCallingConv(Call); + addFnAttr(Context, Call, Attribute::NoUnwind); + return mapValue(BV, Call); + } + case OpFNegate: { + SPIRVUnary *BC = static_cast<SPIRVUnary *>(BV); + return mapValue( + BV, BinaryOperator::CreateFNeg(transValue(BC->getOperand(0), F, BB), + BV->getName(), BB)); + } + + case OpNot: { + SPIRVUnary *BC = static_cast<SPIRVUnary *>(BV); + return mapValue( + BV, BinaryOperator::CreateNot(transValue(BC->getOperand(0), F, BB), + BV->getName(), BB)); + } + + case OpAll : + case OpAny : + return mapValue(BV, + transOCLAllAny(static_cast<SPIRVInstruction *>(BV), BB)); + + case OpIsFinite : + case OpIsInf : + case OpIsNan : + case OpIsNormal : + case OpSignBitSet : + return mapValue(BV, + transOCLRelational(static_cast<SPIRVInstruction *>(BV), BB)); + case OpEnqueueKernel : + return mapValue(BV, transEnqueueKernelBI( + static_cast<SPIRVInstruction *>(BV), BB)); + case OpGetKernelWorkGroupSize : + case OpGetKernelPreferredWorkGroupSizeMultiple : + return mapValue(BV, transWGSizeBI( + static_cast<SPIRVInstruction *>(BV), BB)); + default: { + auto OC = BV->getOpCode(); + if (isSPIRVCmpInstTransToLLVMInst(static_cast<SPIRVInstruction*>(BV))) { + return mapValue(BV, transCmpInst(BV, BB, F)); + } else if ((OCLSPIRVBuiltinMap::rfind(OC, nullptr) || + isIntelSubgroupOpCode(OC)) && + !isAtomicOpCode(OC) && + !isGroupOpCode(OC) && + !isPipeOpCode(OC)) { + return mapValue(BV, transOCLBuiltinFromInst( + static_cast<SPIRVInstruction *>(BV), BB)); + } else if (isBinaryShiftLogicalBitwiseOpCode(OC) || + isLogicalOpCode(OC)) { + return mapValue(BV, transShiftLogicalBitwiseInst(BV, BB, F)); + } else if (isCvtOpCode(OC)) { + auto BI = static_cast<SPIRVInstruction *>(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, transSPIRVBuiltinFromInst( + static_cast<SPIRVInstruction *>(BV), BB)); + } + + SPIRVDBG(spvdbgs() << "Cannot translate " << *BV << '\n';) + llvm_unreachable("Translation of SPIRV instruction not implemented"); + return NULL; + } +} + +template<class SourceTy, class FuncTy> +bool +SPIRVToLLVM::foreachFuncCtlMask(SourceTy Source, FuncTy Func) { + SPIRVWord FCM = Source->getFuncCtlMask(); + SPIRSPIRVFuncCtlMaskMap::foreach([&](Attribute::AttrKind Attr, + SPIRVFunctionControlMaskKind Mask){ + if (FCM & Mask) + Func(Attr); + }); + return true; +} + +Function * +SPIRVToLLVM::transFunction(SPIRVFunction *BF) { + auto Loc = FuncMap.find(BF); + if (Loc != FuncMap.end()) + return Loc->second; + + auto IsKernel = BM->isEntryPoint(ExecutionModelKernel, BF->getId()); + auto Linkage = IsKernel ? GlobalValue::ExternalLinkage : transLinkageType(BF); + FunctionType *FT = dyn_cast<FunctionType>(transType(BF->getFunctionType())); + Function *F = dyn_cast<Function>(mapValue(BF, Function::Create(FT, Linkage, + BF->getName(), M))); + assert(F); + mapFunction(BF, F); + if (!F->isIntrinsic()) { + F->setCallingConv(IsKernel ? CallingConv::SPIR_KERNEL : + CallingConv::SPIR_FUNC); + if (isFuncNoUnwind()) + F->addFnAttr(Attribute::NoUnwind); + foreachFuncCtlMask(BF, [&](Attribute::AttrKind Attr){ + F->addFnAttr(Attr); + }); + } + + for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; + ++I) { + auto BA = BF->getArgument(I->getArgNo()); + mapValue(BA, &(*I)); + setName(&(*I), BA); + BA->foreachAttr([&](SPIRVFuncParamAttrKind Kind){ + if (Kind == FunctionParameterAttributeNoWrite) + return; + F->addAttribute(I->getArgNo() + 1, SPIRSPIRVFuncParamAttrMap::rmap(Kind)); + }); + + SPIRVWord MaxOffset = 0; + if (BA->hasDecorate(DecorationMaxByteOffset, 0, &MaxOffset)) { + AttrBuilder Builder; + Builder.addDereferenceableAttr(MaxOffset); + I->addAttrs(Builder); + } + } + BF->foreachReturnValueAttr([&](SPIRVFuncParamAttrKind Kind){ + if (Kind == FunctionParameterAttributeNoWrite) + return; + F->addAttribute(AttributeList::ReturnIndex, + SPIRSPIRVFuncParamAttrMap::rmap(Kind)); + }); + + // Creating all basic blocks before creating instructions. + for (size_t I = 0, E = BF->getNumBasicBlock(); I != E; ++I) { + transValue(BF->getBasicBlock(I), F, nullptr); + } + + for (size_t I = 0, E = BF->getNumBasicBlock(); I != E; ++I) { + SPIRVBasicBlock *BBB = BF->getBasicBlock(I); + BasicBlock *BB = dyn_cast<BasicBlock>(transValue(BBB, F, nullptr)); + for (size_t BI = 0, BE = BBB->getNumInst(); BI != BE; ++BI) { + SPIRVInstruction *BInst = BBB->getInst(BI); + transValue(BInst, F, BB, false); + } + } + return F; +} + +/// LLVM convert builtin functions is translated to two instructions: +/// y = i32 islessgreater(float x, float z) -> +/// y = i32 ZExt(bool LessGreater(float x, float z)) +/// When translating back, for simplicity, a trunc instruction is inserted +/// w = bool LessGreater(float x, float z) -> +/// w = bool Trunc(i32 islessgreater(float x, float z)) +/// Optimizer should be able to remove the redundant trunc/zext +void +SPIRVToLLVM::transOCLBuiltinFromInstPreproc(SPIRVInstruction* BI, Type *&RetTy, + std::vector<SPIRVValue *> &Args) { + if (!BI->hasType()) + return; + auto BT = BI->getType(); + auto OC = BI->getOpCode(); + if (isCmpOpCode(BI->getOpCode())) { + if (BT->isTypeBool()) + RetTy = IntegerType::getInt32Ty(*Context); + else if (BT->isTypeVectorBool()) + RetTy = VectorType::get(IntegerType::get(*Context, + Args[0]->getType()->getVectorComponentType()->isTypeFloat(64)?64:32), + BT->getVectorComponentCount()); + else + llvm_unreachable("invalid compare instruction"); + } else if (OC == OpGenericCastToPtrExplicit) + Args.pop_back(); + else if (OC == OpImageRead && Args.size() > 2) { + // Drop "Image operands" argument + Args.erase(Args.begin() + 2); + } +} + +Instruction* +SPIRVToLLVM::transOCLBuiltinPostproc(SPIRVInstruction* BI, + CallInst* CI, BasicBlock* BB, const std::string &DemangledName) { + auto OC = BI->getOpCode(); + if (isCmpOpCode(OC) && + BI->getType()->isTypeVectorOrScalarBool()) { + return CastInst::Create(Instruction::Trunc, CI, transType(BI->getType()), + "cvt", BB); + } + if (OC == OpImageSampleExplicitLod) + return postProcessOCLReadImage(BI, CI, DemangledName); + if (OC == OpImageWrite) { + return postProcessOCLWriteImage(BI, CI, DemangledName); + } + if (OC == OpGenericPtrMemSemantics) + return BinaryOperator::CreateShl(CI, getInt32(M, 8), "", BB); + if (OC == OpImageQueryFormat) + return BinaryOperator::CreateSub( + CI, getInt32(M, OCLImageChannelDataTypeOffset), "", BB); + if (OC == OpImageQueryOrder) + return BinaryOperator::CreateSub( + CI, getInt32(M, OCLImageChannelOrderOffset), "", BB); + if (OC == OpBuildNDRange) + return postProcessOCLBuildNDRange(BI, CI, DemangledName); + if (OC == OpGroupAll || OC == OpGroupAny) + return postProcessGroupAllAny(CI, DemangledName); + if (SPIRVEnableStepExpansion && + (DemangledName == "smoothstep" || + DemangledName == "step")) + return expandOCLBuiltinWithScalarArg(CI, DemangledName); + return CI; +} + +static void adaptBlockInvoke(Function *Invoke, Type *BlockStructTy) { + // As first argument block invoke takes a pointer to captured data. + // We pass to block invoke whole block structure, not only captured data + // as it expected. So we need to update original function to unpack expected + // captured data and use it instead of an original argument + // + // %block = bitcast i8 addrspace(4)* to <{ ..., [X x i8] }> addrspace(4)* + // %block.1 = addrspacecast %block to <{ ..., [X x i8] }>* + // %captured = getelementptr <{ ..., [X x i8] }>, i32 0, i32 5 + // %captured.1 = bitcast %captured to i8* + + BasicBlock *BB = &(Invoke->getEntryBlock()); + BB->splitBasicBlock(BB->begin(), "invoke"); + auto FirstArg = &*(Invoke->arg_begin()); + IRBuilder<> Builder(BB, BB->begin()); + + auto FirstArgTy = dyn_cast<PointerType>(FirstArg->getType()); + assert(FirstArgTy && "Expects that first argument of invoke is a pointer"); + unsigned FirstArgAS = FirstArgTy->getAddressSpace(); + + auto Int8PtrTy = + Type::getInt8PtrTy(Invoke->getParent()->getContext(), FirstArgAS); + auto BlockStructPtrTy = PointerType::get(BlockStructTy, FirstArgAS); + + auto Int32Ty = Type::getInt32Ty(Invoke->getParent()->getContext()); + Value *CapturedGEPIndices[2] = { ConstantInt::get(Int32Ty, 0), + ConstantInt::get(Int32Ty, 5) }; + auto BlockToStructCast = + Builder.CreateBitCast(FirstArg, BlockStructPtrTy, "block"); + auto CapturedGEP = Builder.CreateGEP(BlockToStructCast, CapturedGEPIndices); + auto CapturedToInt8Cast = Builder.CreateBitCast(CapturedGEP, Int8PtrTy); + + FirstArg->replaceUsesOutsideBlock(CapturedToInt8Cast, BB); +} + +static Type *getOrCreateBlockDescTy(Module *M) { + // Get or create block descriptor type which contains block size + // in the last element: %struct.__block_descriptor = type { i64, i64 } + auto BlockDescTy = M->getTypeByName("struct.__block_descriptor"); + if (BlockDescTy) + return BlockDescTy; + + auto Int64Ty = Type::getInt64Ty(M->getContext()); + Type *BlockDescElements[2] = {/*Reserved*/ Int64Ty, /*Block size*/ Int64Ty }; + return StructType::create(M->getContext(), BlockDescElements, + "struct.__block_descriptor"); +} + +Value * +SPIRVToLLVM::transEnqueuedBlock(SPIRVValue *SInvoke, SPIRVValue *SCaptured, + SPIRVValue *SCaptSize, SPIRVValue *SCaptAlignment, + Function *LBI, BasicBlock *LBB) { + // Search if that block have been already translated + auto Loc = BlockMap.find(SInvoke); + if (Loc != BlockMap.end()) + return Loc->second; + + IRBuilder<> Builder(LBB); + const DataLayout &DL = M->getDataLayout(); + + // Translate block and its arguments from SPIRV values to LLVM + auto LInvoke = transFunction(static_cast<SPIRVFunction *>(SInvoke)); + auto LCaptured = transValue(SCaptured, LBI, LBB, false); + auto LCaptSize = + dyn_cast<ConstantInt>(transValue(SCaptSize, LBI, LBB, false)); + auto LCaptAlignment = + dyn_cast<ConstantInt>(transValue(SCaptAlignment, LBI, LBB, false)); + + // Create basic types + auto Int8Ty = Type::getInt8Ty(*Context); + auto Int32Ty = Type::getInt32Ty(*Context); + auto Int8PtrTy = Type::getInt8PtrTy(*Context, SPIRAS_Private); + auto Int8PtrTyGen = Type::getInt8PtrTy(*Context, SPIRAS_Generic); + auto BlockDescTy = getOrCreateBlockDescTy(M); + auto BlockDescPtrTy = BlockDescTy->getPointerTo(SPIRAS_Private); + + // Create a block as structure: + // <{ i8*, i32, i32, i8*, %struct.__block_descriptor* }> + SmallVector<Type *, 8> BlockEls = + { /*isa*/ Int8PtrTy, /*flags*/ Int32Ty, /*reserved*/ Int32Ty, + /*invoke*/ Int8PtrTy, /*block_descriptor*/ BlockDescPtrTy }; + + // Add captured if any + // <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, [X x i8] }> + // Note: captured data stored in structure as array of char + if (LCaptSize->getZExtValue() > 0) + BlockEls.push_back(ArrayType::get(Int8Ty, LCaptSize->getZExtValue())); + + auto BlockTy = StructType::get(*Context, BlockEls, /*isPacked*/ true); + + // Allocate block on the stack, then store data to it + auto BlockAlloca = Builder.CreateAlloca(BlockTy, nullptr, "block"); + BlockAlloca->setAlignment(DL.getPrefTypeAlignment(BlockTy)); + + auto getIndices = [Int32Ty](int a, int b) -> SmallVector<Value *, 2> { + return { ConstantInt::get(Int32Ty, a), ConstantInt::get(Int32Ty, b) }; + }; + + // 1. isa, flags and reserved fields isn't used in current implementation + // Fill them the same way as clang does + auto IsaGEP = Builder.CreateGEP(BlockAlloca, getIndices(0, 0)); + Builder.CreateStore(ConstantPointerNull::get(Int8PtrTy), IsaGEP); + auto FlagsGEP = Builder.CreateGEP(BlockAlloca, getIndices(0, 1)); + Builder.CreateStore(ConstantInt::get(Int32Ty, 1342177280), FlagsGEP); + auto ReservedGEP = Builder.CreateGEP(BlockAlloca, getIndices(0, 2)); + Builder.CreateStore(ConstantInt::get(Int32Ty, 0), ReservedGEP); + + // 2. Store pointer to block invoke to the structure + auto InvokeCast = Builder.CreateBitCast(LInvoke, Int8PtrTy, "invoke"); + auto InvokeGEP = Builder.CreateGEP(BlockAlloca, getIndices(0, 3)); + Builder.CreateStore(InvokeCast, InvokeGEP); + + // 3. Create and store a pointer to the block descriptor global value + uint64_t SizeOfBlock = DL.getTypeAllocSize(BlockTy); + + auto Int64Ty = Type::getInt64Ty(*Context); + Constant *BlockDescEls[2] = { ConstantInt::get(Int64Ty, 0), + ConstantInt::get(Int64Ty, SizeOfBlock) }; + auto BlockDesc = + ConstantStruct::get(dyn_cast<StructType>(BlockDescTy), BlockDescEls); + + auto BlockDescGV = + new GlobalVariable(*M, BlockDescTy, true, GlobalValue::InternalLinkage, + BlockDesc, "__block_descriptor_spirv"); + auto BlockDescGEP = + Builder.CreateGEP(BlockAlloca, getIndices(0, 4), "block.descriptor"); + Builder.CreateStore(BlockDescGV, BlockDescGEP); + + // 4. Copy captured data to the structure + if (LCaptSize->getZExtValue() > 0) { + auto CapturedGEP = + Builder.CreateGEP(BlockAlloca, getIndices(0, 5), "block.captured"); + auto CapturedGEPCast = Builder.CreateBitCast(CapturedGEP, Int8PtrTy); + + // We can't make any guesses about type of captured data, so + // let's copy it through memcpy + Builder.CreateMemCpy(CapturedGEPCast, LCaptAlignment->getZExtValue(), + LCaptured, LCaptAlignment->getZExtValue(), LCaptSize, + SCaptured->isVolatile()); + + // Fix invoke function to correctly process its first argument + adaptBlockInvoke(LInvoke, BlockTy); + } + auto BlockCast = Builder.CreateBitCast(BlockAlloca, Int8PtrTy); + auto BlockCastGen = Builder.CreateAddrSpaceCast(BlockCast, Int8PtrTyGen); + BlockMap[SInvoke] = BlockCastGen; + return BlockCastGen; +} + +Instruction * +SPIRVToLLVM::transEnqueueKernelBI(SPIRVInstruction *BI, BasicBlock *BB) { + Type *IntTy = Type::getInt32Ty(*Context); + + // Find or create enqueue kernel BI declaration + auto Ops = BI->getOperands(); + bool hasVaargs = Ops.size() > 10; + + std::string FName = hasVaargs ? "__enqueue_kernel_events_vaargs" + : "__enqueue_kernel_basic_events"; + Function* F = M->getFunction(FName); + if (!F) { + Type *EventTy = PointerType::get( + getOrCreateOpaquePtrType(M, SPIR_TYPE_NAME_CLK_EVENT_T, SPIRAS_Private), + SPIRAS_Generic); + + SmallVector<Type *, 8> Tys = { + transType(Ops[0]->getType()), // queue + IntTy, // flags + transType(Ops[2]->getType()), // ndrange + IntTy, EventTy, EventTy, // events + Type::getInt8PtrTy(*Context, SPIRAS_Generic) // block + }; + if (hasVaargs) + Tys.push_back(IntTy); // Number of variadics if any + + FunctionType* FT = FunctionType::get(IntTy, Tys, hasVaargs); + F = Function::Create(FT, GlobalValue::ExternalLinkage, FName, M); + if (isFuncNoUnwind()) + F->addFnAttr(Attribute::NoUnwind); + } + + // Create call to enqueue kernel BI + SmallVector<Value *, 8> Args = { + transValue(Ops[0], F, BB, false), // queue + transValue(Ops[1], F, BB, false), // flags + transValue(Ops[2], F, BB, false), // ndrange + transValue(Ops[3], F, BB, false), // events number + transDeviceEvent(Ops[4], F, BB), // event_wait_list + transDeviceEvent(Ops[5], F, BB), // event_ret + transEnqueuedBlock(Ops[6], Ops[7], Ops[8], Ops[9], F, BB) // block + }; + + if (hasVaargs) { + Args.push_back(ConstantInt::get(IntTy, Ops.size() - 10)); // Number of vaargs + for (unsigned i = 10; i < Ops.size(); ++i) + Args.push_back(transValue(Ops[i], F, BB, false)); + } + auto Call = CallInst::Create(F, Args, "", BB); + setName(Call, BI); + setAttrByCalledFunc(Call); + return Call; +} + +Instruction * +SPIRVToLLVM::transWGSizeBI(SPIRVInstruction *BI, BasicBlock *BB) { + std::string FName = + (BI->getOpCode() == OpGetKernelWorkGroupSize) + ? "__get_kernel_work_group_size_impl" + : "__get_kernel_preferred_work_group_multiple_impl"; + + Function* F = M->getFunction(FName); + if (!F) { + auto Int8PtrTyGen = Type::getInt8PtrTy(*Context, SPIRAS_Generic); + FunctionType* FT = + FunctionType::get(Type::getInt32Ty(*Context), Int8PtrTyGen, false); + F = Function::Create(FT, GlobalValue::ExternalLinkage, FName, M); + if (isFuncNoUnwind()) + F->addFnAttr(Attribute::NoUnwind); + } + auto Ops = BI->getOperands(); + auto Block = transEnqueuedBlock(Ops[0], Ops[1], Ops[2], Ops[3], F, BB); + auto Call = CallInst::Create(F, Block, "", BB); + setName(Call, BI); + setAttrByCalledFunc(Call); + return Call; +} + +Instruction * +SPIRVToLLVM::transBuiltinFromInst(const std::string& FuncName, + SPIRVInstruction* BI, BasicBlock* BB) { + std::string MangledName; + auto Ops = BI->getOperands(); + Type* RetTy = BI->hasType() ? transType(BI->getType()) : + Type::getVoidTy(*Context); + transOCLBuiltinFromInstPreproc(BI, RetTy, Ops); + std::vector<Type*> ArgTys = transTypeVector( + SPIRVInstruction::getOperandTypes(Ops)); + bool HasFuncPtrArg = false; + for (auto& I:ArgTys) { + if (isa<FunctionType>(I)) { + I = PointerType::get(I, SPIRAS_Private); + HasFuncPtrArg = true; + } + } + if (!HasFuncPtrArg) + MangleOpenCLBuiltin(FuncName, ArgTys, MangledName); + else + MangledName = decorateSPIRVFunction(FuncName); + Function* Func = M->getFunction(MangledName); + FunctionType* FT = FunctionType::get(RetTy, ArgTys, false); + // ToDo: Some intermediate functions have duplicate names with + // different function types. This is OK if the function name + // is used internally and finally translated to unique function + // names. However it is better to have a way to differentiate + // between intermidiate functions and final functions and make + // sure final functions have unique names. + SPIRVDBG( + if (!HasFuncPtrArg && Func && Func->getFunctionType() != FT) { + dbgs() << "Warning: Function name conflict:\n" + << *Func << '\n' + << " => " << *FT << '\n'; + } + ) + if (!Func || Func->getFunctionType() != FT) { + DEBUG(for (auto& I:ArgTys) { + dbgs() << *I << '\n'; + }); + Func = Function::Create(FT, GlobalValue::ExternalLinkage, MangledName, M); + Func->setCallingConv(CallingConv::SPIR_FUNC); + if (isFuncNoUnwind()) + Func->addFnAttr(Attribute::NoUnwind); + } + auto Call = CallInst::Create(Func, + transValue(Ops, BB->getParent(), BB), "", BB); + setName(Call, BI); + setAttrByCalledFunc(Call); + SPIRVDBG(spvdbgs() << "[transInstToBuiltinCall] " << *BI << " -> "; dbgs() << + *Call << '\n';) + Instruction *Inst = Call; + Inst = transOCLBuiltinPostproc(BI, Call, BB, FuncName); + return Inst; +} + +std::string +SPIRVToLLVM::getOCLBuiltinName(SPIRVInstruction* BI) { + auto OC = BI->getOpCode(); + if (OC == OpGenericCastToPtrExplicit) + return getOCLGenericCastToPtrName(BI); + if (isCvtOpCode(OC)) + return getOCLConvertBuiltinName(BI); + if (OC == OpBuildNDRange) { + auto NDRangeInst = static_cast<SPIRVBuildNDRange *>(BI); + auto EleTy = ((NDRangeInst->getOperands())[0])->getType(); + int Dim = EleTy->isTypeArray() ? EleTy->getArrayLength() : 1; + // cygwin does not have std::to_string + ostringstream OS; + OS << Dim; + assert((EleTy->isTypeInt() && Dim == 1) || + (EleTy->isTypeArray() && Dim >= 2 && Dim <= 3)); + return std::string(kOCLBuiltinName::NDRangePrefix) + OS.str() + "D"; + } + if (isIntelSubgroupOpCode(OC)) { + std::stringstream Name; + SPIRVType *DataTy = nullptr; + switch (OC) { + case OpSubgroupBlockReadINTEL: + case OpSubgroupImageBlockReadINTEL: + Name << "intel_sub_group_block_read"; + DataTy = BI->getType(); + break; + case OpSubgroupBlockWriteINTEL: + Name << "intel_sub_group_block_write"; + DataTy = BI->getOperands()[1]->getType(); + break; + case OpSubgroupImageBlockWriteINTEL: + Name << "intel_sub_group_block_write"; + DataTy = BI->getOperands()[2]->getType(); + break; + default: + return OCLSPIRVBuiltinMap::rmap(OC); + } + if (DataTy) { + if (DataTy->getBitWidth() == 16) + Name << "_us"; + if (DataTy->isTypeVector()) { + if (unsigned ComponentCount = DataTy->getVectorComponentCount()) + Name << ComponentCount; + } + } + return Name.str(); + } + auto Name = OCLSPIRVBuiltinMap::rmap(OC); + + SPIRVType *T = nullptr; + switch(OC) { + case OpImageRead: + T = BI->getType(); + break; + case OpImageWrite: + T = BI->getOperands()[2]->getType(); + break; + default: + // do nothing + break; + } + if (T && T->isTypeVector()) + T = T->getVectorComponentType(); + if (T) + Name += T->isTypeFloat()?'f':'i'; + + return Name; +} + +Instruction * +SPIRVToLLVM::transOCLBuiltinFromInst(SPIRVInstruction *BI, BasicBlock *BB) { + assert(BB && "Invalid BB"); + auto FuncName = getOCLBuiltinName(BI); + return transBuiltinFromInst(FuncName, BI, BB); +} + +Instruction * +SPIRVToLLVM::transSPIRVBuiltinFromInst(SPIRVInstruction *BI, BasicBlock *BB) { + assert(BB && "Invalid BB"); + string Suffix = ""; + if (BI->getOpCode() == OpCreatePipeFromPipeStorage) { + auto CPFPS = static_cast<SPIRVCreatePipeFromPipeStorage*>(BI); + assert(CPFPS->getType()->isTypePipe() && + "Invalid type of CreatePipeFromStorage"); + auto PipeType = static_cast<SPIRVTypePipe*>(CPFPS->getType()); + switch (PipeType->getAccessQualifier()) { + default: + case AccessQualifierReadOnly: Suffix = "_read"; break; + case AccessQualifierWriteOnly: Suffix = "_write"; break; + case AccessQualifierReadWrite: Suffix = "_read_write"; break; + } + } + + return transBuiltinFromInst(getSPIRVFuncName(BI->getOpCode(), Suffix), BI, BB); +} + +bool +SPIRVToLLVM::translate() { + if (!transAddressingModel()) + return false; + + DbgTran.createCompileUnit(); + DbgTran.addDbgInfoVersion(); + + for (unsigned I = 0, E = BM->getNumVariables(); I != E; ++I) { + auto BV = BM->getVariable(I); + if (BV->getStorageClass() != StorageClassFunction) + transValue(BV, nullptr, nullptr); + } + + for (unsigned I = 0, E = BM->getNumFunctions(); I != E; ++I) { + transFunction(BM->getFunction(I)); + } + if (!transKernelMetadata()) + return false; + if (!transFPContractMetadata()) + return false; + if (!transSourceLanguage()) + return false; + if (!transSourceExtension()) + return false; + transGeneratorMD(); + if (!transOCLBuiltinsFromVariables()) + return false; + if (!postProcessOCL()) + return false; + eraseUselessFunctions(M); + DbgTran.finalize(); + return true; +} + +bool +SPIRVToLLVM::transAddressingModel() { + switch (BM->getAddressingModel()) { + case AddressingModelPhysical64: + M->setTargetTriple(SPIR_TARGETTRIPLE64); + M->setDataLayout(SPIR_DATALAYOUT64); + break; + case AddressingModelPhysical32: + M->setTargetTriple(SPIR_TARGETTRIPLE32); + M->setDataLayout(SPIR_DATALAYOUT32); + break; + case AddressingModelLogical: + // Do not set target triple and data layout + break; + default: + SPIRVCKRT(0, InvalidAddressingModel, "Actual addressing mode is " + + (unsigned)BM->getAddressingModel()); + } + return true; +} + +bool +SPIRVToLLVM::transDecoration(SPIRVValue *BV, Value *V) { + if (!transAlign(BV, V)) + return false; + DbgTran.transDbgInfo(BV, V); + return true; +} + +bool +SPIRVToLLVM::transFPContractMetadata() { + bool ContractOff = false; + for (unsigned I = 0, E = BM->getNumFunctions(); I != E; ++I) { + SPIRVFunction *BF = BM->getFunction(I); + if (!isOpenCLKernel(BF)) + continue; + if (BF->getExecutionMode(ExecutionModeContractionOff)) { + ContractOff = true; + break; + } + } + if (!ContractOff) + M->getOrInsertNamedMetadata(kSPIR2MD::FPContract); + return true; +} + +std::string SPIRVToLLVM::transOCLImageTypeAccessQualifier( + SPIRV::SPIRVTypeImage* ST) { + return SPIRSPIRVAccessQualifierMap::rmap(ST->hasAccessQualifier() ? + ST->getAccessQualifier() : AccessQualifierReadOnly); +} + +bool +SPIRVToLLVM::transNonTemporalMetadata(Instruction *I) { + Constant* One = ConstantInt::get(Type::getInt32Ty(*Context), 1); + MDNode *Node = MDNode::get(*Context, ConstantAsMetadata::get(One)); + I->setMetadata(M->getMDKindID("nontemporal"), Node); + return true; +} + +bool +SPIRVToLLVM::transKernelMetadata() { + for (unsigned I = 0, E = BM->getNumFunctions(); I != E; ++I) { + SPIRVFunction *BF = BM->getFunction(I); + Function *F = static_cast<Function *>(getTranslatedValue(BF)); + assert(F && "Invalid translated function"); + if (F->getCallingConv() != CallingConv::SPIR_KERNEL) + continue; + + // Generate metadata for kernel_arg_address_spaces + addOCLKernelArgumentMetadata(Context, SPIR_MD_KERNEL_ARG_ADDR_SPACE, BF, F, + [=](SPIRVFunctionParameter *Arg){ + SPIRVType *ArgTy = Arg->getType(); + SPIRAddressSpace AS = SPIRAS_Private; + if (ArgTy->isTypePointer()) + AS = SPIRSPIRVAddrSpaceMap::rmap(ArgTy->getPointerStorageClass()); + else if (ArgTy->isTypeOCLImage() || ArgTy->isTypePipe()) + AS = SPIRAS_Global; + return ConstantAsMetadata::get( + ConstantInt::get(Type::getInt32Ty(*Context), AS)); + }); + // Generate metadata for kernel_arg_access_qual + addOCLKernelArgumentMetadata(Context, SPIR_MD_KERNEL_ARG_ACCESS_QUAL, BF, F, + [=](SPIRVFunctionParameter *Arg){ + std::string Qual; + auto T = Arg->getType(); + if (T->isTypeOCLImage()) { + auto ST = static_cast<SPIRVTypeImage *>(T); + Qual = transOCLImageTypeAccessQualifier(ST); + } else if (T->isTypePipe()){ + auto PT = static_cast<SPIRVTypePipe *>(T); + Qual = transOCLPipeTypeAccessQualifier(PT); + } else + Qual = "none"; + return MDString::get(*Context, Qual); + }); + // Generate metadata for kernel_arg_type + addOCLKernelArgumentMetadata(Context, SPIR_MD_KERNEL_ARG_TYPE, BF, F, + [=](SPIRVFunctionParameter *Arg){ + return transOCLKernelArgTypeName(Arg); + }); + // Generate metadata for kernel_arg_type_qual + addOCLKernelArgumentMetadata(Context, SPIR_MD_KERNEL_ARG_TYPE_QUAL, BF, F, + [=](SPIRVFunctionParameter *Arg){ + std::string Qual; + if (Arg->hasDecorate(DecorationVolatile)) + Qual = kOCLTypeQualifierName::Volatile; + Arg->foreachAttr([&](SPIRVFuncParamAttrKind Kind){ + Qual += Qual.empty() ? "" : " "; + switch(Kind){ + case FunctionParameterAttributeNoAlias: + Qual += kOCLTypeQualifierName::Restrict; + break; + case FunctionParameterAttributeNoWrite: + Qual += kOCLTypeQualifierName::Const; + break; + default: + // do nothing. + break; + } + }); + if (Arg->getType()->isTypePipe()) { + Qual += Qual.empty() ? "" : " "; + Qual += kOCLTypeQualifierName::Pipe; + } + return MDString::get(*Context, Qual); + }); + // Generate metadata for kernel_arg_base_type + addOCLKernelArgumentMetadata(Context, SPIR_MD_KERNEL_ARG_BASE_TYPE, BF, F, + [=](SPIRVFunctionParameter *Arg){ + return transOCLKernelArgTypeName(Arg); + }); + // Generate metadata for kernel_arg_name + if (SPIRVGenKernelArgNameMD) { + bool ArgHasName = true; + BF->foreachArgument([&](SPIRVFunctionParameter *Arg){ + ArgHasName &= !Arg->getName().empty(); + }); + if (ArgHasName) + addOCLKernelArgumentMetadata(Context, SPIR_MD_KERNEL_ARG_NAME, BF, F, + [=](SPIRVFunctionParameter *Arg){ + return MDString::get(*Context, Arg->getName()); + }); + } + // Generate metadata for reqd_work_group_size + if (auto EM = BF->getExecutionMode(ExecutionModeLocalSize)) { + F->setMetadata(kSPIR2MD::WGSize, + getMDNodeStringIntVec(Context, EM->getLiterals())); + } + // Generate metadata for work_group_size_hint + if (auto EM = BF->getExecutionMode(ExecutionModeLocalSizeHint)) { + F->setMetadata(kSPIR2MD::WGSizeHint, + getMDNodeStringIntVec(Context, EM->getLiterals())); + } + // Generate metadata for vec_type_hint + if (auto EM = BF->getExecutionMode(ExecutionModeVecTypeHint)) { + std::vector<Metadata*> MetadataVec; + Type *VecHintTy = decodeVecTypeHint(*Context, EM->getLiterals()[0]); + assert(VecHintTy); + MetadataVec.push_back(ValueAsMetadata::get(UndefValue::get(VecHintTy))); + MetadataVec.push_back( + ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(*Context), + 1))); + F->setMetadata(kSPIR2MD::VecTyHint, MDNode::get(*Context, MetadataVec)); + } + } + return true; +} + +bool +SPIRVToLLVM::transAlign(SPIRVValue *BV, Value *V) { + if (auto AL = dyn_cast<AllocaInst>(V)) { + SPIRVWord Align = 0; + if (BV->hasAlignment(&Align)) + AL->setAlignment(Align); + return true; + } + if (auto GV = dyn_cast<GlobalVariable>(V)) { + SPIRVWord Align = 0; + if (BV->hasAlignment(&Align)) + GV->setAlignment(Align); + return true; + } + return true; +} + +void +SPIRVToLLVM::transOCLVectorLoadStore(std::string& UnmangledName, + std::vector<SPIRVWord> &BArgs) { + if (UnmangledName.find("vload") == 0 && + UnmangledName.find("n") != std::string::npos) { + if (BArgs.back() != 1) { + std::stringstream SS; + SS << BArgs.back(); + UnmangledName.replace(UnmangledName.find("n"), 1, SS.str()); + } else { + UnmangledName.erase(UnmangledName.find("n"), 1); + } + BArgs.pop_back(); + } else if (UnmangledName.find("vstore") == 0) { + if (UnmangledName.find("n") != std::string::npos) { + auto T = BM->getValueType(BArgs[0]); + if (T->isTypeVector()) { + auto W = T->getVectorComponentCount(); + std::stringstream SS; + SS << W; + UnmangledName.replace(UnmangledName.find("n"), 1, SS.str()); + } else { + UnmangledName.erase(UnmangledName.find("n"), 1); + } + } + if (UnmangledName.find("_r") != std::string::npos) { + UnmangledName.replace(UnmangledName.find("_r"), 2, std::string("_") + + SPIRSPIRVFPRoundingModeMap::rmap(static_cast<SPIRVFPRoundingModeKind>( + BArgs.back()))); + BArgs.pop_back(); + } + } +} + +// printf is not mangled. The function type should have just one argument. +// read_image*: the second argument should be mangled as sampler. +Instruction * +SPIRVToLLVM::transOCLBuiltinFromExtInst(SPIRVExtInst *BC, BasicBlock *BB) { + assert(BB && "Invalid BB"); + std::string MangledName; + SPIRVWord EntryPoint = BC->getExtOp(); + bool IsVarArg = false; + bool IsPrintf = false; + std::string UnmangledName; + auto BArgs = BC->getArguments(); + + assert(BM->getBuiltinSet(BC->getExtSetId()) == SPIRVEIS_OpenCL && + "Not OpenCL extended instruction"); + if (EntryPoint == OpenCLLIB::Printf) + IsPrintf = true; + else { + UnmangledName = OCLExtOpMap::map(static_cast<OCLExtOpKind>( + EntryPoint)); + } + + SPIRVDBG(spvdbgs() << "[transOCLBuiltinFromExtInst] OrigUnmangledName: " << + UnmangledName << '\n'); + transOCLVectorLoadStore(UnmangledName, BArgs); + + std::vector<Type *> ArgTypes = transTypeVector(BC->getValueTypes(BArgs)); + + if (IsPrintf) { + MangledName = "printf"; + IsVarArg = true; + ArgTypes.resize(1); + } else if (UnmangledName.find("read_image") == 0) { + auto ModifiedArgTypes = ArgTypes; + ModifiedArgTypes[1] = getOrCreateOpaquePtrType(M, "opencl.sampler_t"); + MangleOpenCLBuiltin(UnmangledName, ModifiedArgTypes, MangledName); + } else { + MangleOpenCLBuiltin(UnmangledName, ArgTypes, MangledName); + } + SPIRVDBG(spvdbgs() << "[transOCLBuiltinFromExtInst] ModifiedUnmangledName: " << + UnmangledName << " MangledName: " << MangledName << '\n'); + + FunctionType *FT = FunctionType::get( + transType(BC->getType()), + ArgTypes, + IsVarArg); + Function *F = M->getFunction(MangledName); + if (!F) { + F = Function::Create(FT, + GlobalValue::ExternalLinkage, + MangledName, + M); + F->setCallingConv(CallingConv::SPIR_FUNC); + if (isFuncNoUnwind()) + F->addFnAttr(Attribute::NoUnwind); + } + auto Args = transValue(BC->getValues(BArgs), F, BB); + SPIRVDBG(dbgs() << "[transOCLBuiltinFromExtInst] Function: " << *F << + ", Args: "; + for (auto &I:Args) dbgs() << *I << ", "; dbgs() << '\n'); + CallInst *Call = CallInst::Create(F, + Args, + BC->getName(), + BB); + setCallingConv(Call); + addFnAttr(Context, Call, Attribute::NoUnwind); + return transOCLBuiltinPostproc(BC, Call, BB, UnmangledName); +} + +CallInst * +SPIRVToLLVM::transOCLBarrier(BasicBlock *BB, SPIRVWord ExecScope, + SPIRVWord MemSema, SPIRVWord MemScope) { + SPIRVWord Ver = 0; + BM->getSourceLanguage(&Ver); + + Type* Int32Ty = Type::getInt32Ty(*Context); + Type* VoidTy = Type::getVoidTy(*Context); + + std::string FuncName; + SmallVector<Type *, 2> ArgTy; + SmallVector<Value *, 2> Arg; + + Constant *MemFenceFlags = + ConstantInt::get(Int32Ty, rmapBitMask<OCLMemFenceMap>(MemSema)); + + FuncName = (ExecScope == ScopeWorkgroup) ? kOCLBuiltinName::WorkGroupBarrier + : kOCLBuiltinName::SubGroupBarrier; + + if (ExecScope == ScopeWorkgroup && Ver > 0 && Ver <= kOCLVer::CL12) { + FuncName = kOCLBuiltinName::Barrier; + ArgTy.push_back(Int32Ty); + Arg.push_back(MemFenceFlags); + } else { + Constant *Scope = ConstantInt::get(Int32Ty, OCLMemScopeMap::rmap( + static_cast<spv::Scope>(MemScope))); + + ArgTy.append(2, Int32Ty); + Arg.push_back(MemFenceFlags); + Arg.push_back(Scope); + } + + std::string MangledName; + + MangleOpenCLBuiltin(FuncName, ArgTy, MangledName); + Function *Func = M->getFunction(MangledName); + if (!Func) { + FunctionType *FT = FunctionType::get(VoidTy, ArgTy, false); + Func = Function::Create(FT, GlobalValue::ExternalLinkage, MangledName, M); + Func->setCallingConv(CallingConv::SPIR_FUNC); + if (isFuncNoUnwind()) + Func->addFnAttr(Attribute::NoUnwind); + } + + return CallInst::Create(Func, Arg, "", BB); +} + +CallInst * +SPIRVToLLVM::transOCLMemFence(BasicBlock *BB, + SPIRVWord MemSema, SPIRVWord MemScope) { + SPIRVWord Ver = 0; + BM->getSourceLanguage(&Ver); + + Type* Int32Ty = Type::getInt32Ty(*Context); + Type* VoidTy = Type::getVoidTy(*Context); + + std::string FuncName; + SmallVector<Type *, 3> ArgTy; + SmallVector<Value *, 3> Arg; + + Constant *MemFenceFlags = + ConstantInt::get(Int32Ty, rmapBitMask<OCLMemFenceMap>(MemSema)); + + if (Ver > 0 && Ver <= kOCLVer::CL12) { + FuncName = kOCLBuiltinName::MemFence; + ArgTy.push_back(Int32Ty); + Arg.push_back(MemFenceFlags); + } else { + Constant *Order = + ConstantInt::get(Int32Ty, mapSPIRVMemOrderToOCL(MemSema)); + + Constant *Scope = ConstantInt::get(Int32Ty, OCLMemScopeMap::rmap( + static_cast<spv::Scope>(MemScope))); + + FuncName = kOCLBuiltinName::AtomicWorkItemFence; + ArgTy.append(3, Int32Ty); + Arg.push_back(MemFenceFlags); + Arg.push_back(Order); + Arg.push_back(Scope); + } + + std::string MangledName; + + MangleOpenCLBuiltin(FuncName, ArgTy, MangledName); + Function *Func = M->getFunction(MangledName); + if (!Func) { + FunctionType *FT = FunctionType::get(VoidTy, ArgTy, false); + Func = Function::Create(FT, GlobalValue::ExternalLinkage, MangledName, M); + Func->setCallingConv(CallingConv::SPIR_FUNC); + if (isFuncNoUnwind()) + Func->addFnAttr(Attribute::NoUnwind); + } + + return CallInst::Create(Func, Arg, "", BB); +} + +Instruction * +SPIRVToLLVM::transOCLBarrierFence(SPIRVInstruction *MB, BasicBlock *BB) { + assert(BB && "Invalid BB"); + std::string FuncName; + auto getIntVal = [](SPIRVValue *value){ + return static_cast<SPIRVConstant*>(value)->getZExtIntValue(); + }; + + CallInst* Call = nullptr; + + if (MB->getOpCode() == OpMemoryBarrier) { + auto MemB = static_cast<SPIRVMemoryBarrier*>(MB); + + SPIRVWord MemScope = getIntVal(MemB->getOpValue(0)); + SPIRVWord MemSema = getIntVal(MemB->getOpValue(1)); + + Call = transOCLMemFence(BB, MemSema, MemScope); + } else if (MB->getOpCode() == OpControlBarrier) { + auto CtlB = static_cast<SPIRVControlBarrier*>(MB); + + SPIRVWord ExecScope = getIntVal(CtlB->getExecScope()); + SPIRVWord MemSema = getIntVal(CtlB->getMemSemantic()); + SPIRVWord MemScope = getIntVal(CtlB->getMemScope()); + + Call = transOCLBarrier(BB, ExecScope, MemSema, MemScope); + } else { + llvm_unreachable("Invalid instruction"); + } + + setName(Call, MB); + setAttrByCalledFunc(Call); + SPIRVDBG(spvdbgs() << "[transBarrier] " << *MB << " -> "; + dbgs() << *Call << '\n';) + + return Call; +} + +// SPIR-V only contains language version. Use OpenCL language version as +// SPIR version. +bool +SPIRVToLLVM::transSourceLanguage() { + SPIRVWord Ver = 0; + SourceLanguage Lang = BM->getSourceLanguage(&Ver); + assert((Lang == SourceLanguageOpenCL_C || + Lang == SourceLanguageOpenCL_CPP) && "Unsupported source language"); + unsigned short Major = 0; + unsigned char Minor = 0; + unsigned char Rev = 0; + std::tie(Major, Minor, Rev) = decodeOCLVer(Ver); + SPIRVMDBuilder Builder(*M); + Builder.addNamedMD(kSPIRVMD::Source) + .addOp() + .add(Lang) + .add(Ver) + .done(); + // ToDo: Phasing out usage of old SPIR metadata + if (Ver <= kOCLVer::CL12) + addOCLVersionMetadata(Context, M, kSPIR2MD::SPIRVer, 1, 2); + else + addOCLVersionMetadata(Context, M, kSPIR2MD::SPIRVer, 2, 0); + + addOCLVersionMetadata(Context, M, kSPIR2MD::OCLVer, Major, Minor); + return true; +} + +bool +SPIRVToLLVM::transSourceExtension() { + auto ExtSet = rmap<OclExt::Kind>(BM->getExtension()); + auto CapSet = rmap<OclExt::Kind>(BM->getCapability()); + ExtSet.insert(CapSet.begin(), CapSet.end()); + auto OCLExtensions = map<std::string>(ExtSet); + std::set<std::string> OCLOptionalCoreFeatures; + static const char *OCLOptCoreFeatureNames[] = { + "cl_images", "cl_doubles", + }; + for (auto &I : OCLOptCoreFeatureNames) { + auto Loc = OCLExtensions.find(I); + if (Loc != OCLExtensions.end()) { + OCLExtensions.erase(Loc); + OCLOptionalCoreFeatures.insert(I); + } + } + addNamedMetadataStringSet(Context, M, kSPIR2MD::Extensions, OCLExtensions); + addNamedMetadataStringSet(Context, M, kSPIR2MD::OptFeatures, + OCLOptionalCoreFeatures); + return true; +} + +// If the argument is unsigned return uconvert*, otherwise return convert*. +std::string +SPIRVToLLVM::getOCLConvertBuiltinName(SPIRVInstruction* BI) { + auto OC = BI->getOpCode(); + assert(isCvtOpCode(OC) && "Not convert instruction"); + auto U = static_cast<SPIRVUnary *>(BI); + std::string Name; + if (isCvtFromUnsignedOpCode(OC)) + Name = "u"; + Name += "convert_"; + Name += mapSPIRVTypeToOCLType(U->getType(), + !isCvtToUnsignedOpCode(OC)); + SPIRVFPRoundingModeKind Rounding; + if (U->isSaturatedConversion()) + Name += "_sat"; + if (U->hasFPRoundingMode(&Rounding)) { + Name += "_"; + Name += SPIRSPIRVFPRoundingModeMap::rmap(Rounding); + } + return Name; +} + +//Check Address Space of the Pointer Type +std::string +SPIRVToLLVM::getOCLGenericCastToPtrName(SPIRVInstruction* BI) { + auto GenericCastToPtrInst = BI->getType()->getPointerStorageClass(); + switch (GenericCastToPtrInst) { + case StorageClassCrossWorkgroup: + return std::string(kOCLBuiltinName::ToGlobal); + case StorageClassWorkgroup: + return std::string(kOCLBuiltinName::ToLocal); + case StorageClassFunction: + return std::string(kOCLBuiltinName::ToPrivate); + default: + llvm_unreachable("Invalid address space"); + return ""; + } +} + +llvm::GlobalValue::LinkageTypes +SPIRVToLLVM::transLinkageType(const SPIRVValue* V) { + if (V->getLinkageType() == LinkageTypeInternal) { + return GlobalValue::InternalLinkage; + } + else if (V->getLinkageType() == LinkageTypeImport) { + // Function declaration + if (V->getOpCode() == OpFunction) { + if (static_cast<const SPIRVFunction*>(V)->getNumBasicBlock() == 0) + return GlobalValue::ExternalLinkage; + } + // Variable declaration + if (V->getOpCode() == OpVariable) { + if (static_cast<const SPIRVVariable*>(V)->getInitializer() == 0) + return GlobalValue::ExternalLinkage; + } + // Definition + return GlobalValue::AvailableExternallyLinkage; + } + else {// LinkageTypeExport + if (V->getOpCode() == OpVariable) { + if (static_cast<const SPIRVVariable*>(V)->getInitializer() == 0 ) + // Tentative definition + return GlobalValue::CommonLinkage; + } + return GlobalValue::ExternalLinkage; + } +} + +Instruction *SPIRVToLLVM::transOCLAllAny(SPIRVInstruction *I, BasicBlock *BB) { + CallInst *CI = cast<CallInst>(transSPIRVBuiltinFromInst(I, BB)); + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + return cast<Instruction>(mapValue( + I, mutateCallInstOCL( + M, CI, + [=](CallInst *, std::vector<Value *> &Args, llvm::Type *&RetTy) { + Type *Int32Ty = Type::getInt32Ty(*Context); + auto OldArg = CI->getOperand(0); + auto NewArgTy = VectorType::get( + Int32Ty, OldArg->getType()->getVectorNumElements()); + auto NewArg = + CastInst::CreateSExtOrBitCast(OldArg, NewArgTy, "", CI); + Args[0] = NewArg; + RetTy = Int32Ty; + return CI->getCalledFunction()->getName(); + }, + [=](CallInst *NewCI) -> Instruction * { + return CastInst::CreateTruncOrBitCast( + NewCI, Type::getInt1Ty(*Context), "", NewCI->getNextNode()); + }, + &Attrs))); +} + +Instruction *SPIRVToLLVM::transOCLRelational(SPIRVInstruction *I, BasicBlock *BB) { + CallInst *CI = cast<CallInst>(transSPIRVBuiltinFromInst(I, BB)); + AttributeList Attrs = CI->getCalledFunction()->getAttributes(); + return cast<Instruction>(mapValue( + I, mutateCallInstOCL( + M, CI, + [=](CallInst *, std::vector<Value *> &Args, llvm::Type *&RetTy) { + Type *IntTy = Type::getInt32Ty(*Context); + RetTy = IntTy; + if (CI->getType()->isVectorTy()) { + if (cast<VectorType>(CI->getOperand(0)->getType()) + ->getElementType() + ->isDoubleTy()) + IntTy = Type::getInt64Ty(*Context); + if (cast<VectorType>(CI->getOperand(0)->getType()) + ->getElementType() + ->isHalfTy()) + IntTy = Type::getInt16Ty(*Context); + RetTy = VectorType::get(IntTy, + CI->getType()->getVectorNumElements()); + } + return CI->getCalledFunction()->getName(); + }, + [=](CallInst *NewCI) -> Instruction * { + Type *RetTy = Type::getInt1Ty(*Context); + if (NewCI->getType()->isVectorTy()) + RetTy = + VectorType::get(Type::getInt1Ty(*Context), + NewCI->getType()->getVectorNumElements()); + return CastInst::CreateTruncOrBitCast(NewCI, RetTy, "", + NewCI->getNextNode()); + }, + &Attrs))); +} +} + +bool +llvm::ReadSPIRV(LLVMContext &C, std::istream &IS, Module *&M, + std::string &ErrMsg) { + M = new Module("", C); + std::unique_ptr<SPIRVModule> BM(SPIRVModule::createSPIRVModule()); + + IS >> *BM; + + SPIRVToLLVM BTL(M, BM.get()); + bool Succeed = true; + if (!BTL.translate()) { + BM->getError(ErrMsg); + Succeed = false; + } + llvm::legacy::PassManager PassMgr; + PassMgr.add(createSPIRVToOCL20()); + PassMgr.add(createOCL20To12()); + PassMgr.run(*M); + + if (DbgSaveTmpLLVM) + dumpLLVM(M, DbgTmpLLVMFileName); + if (!Succeed) { + delete M; + M = nullptr; + } + return Succeed; +} diff --git a/lib/SPIRV/SPIRVToOCL20.cpp b/lib/SPIRV/SPIRVToOCL20.cpp index 6094cbd..7297526 100644 --- a/lib/SPIRV/SPIRVToOCL20.cpp +++ b/lib/SPIRV/SPIRVToOCL20.cpp @@ -1,4 +1,4 @@ -//===- SPIRVToOCL20.cpp - Transform SPIR-V builtins to OCL20 builtins-------===// +//===- SPIRVToOCL20.cpp - Transform SPIR-V builtins to OCL20 builtins-------===// // // The LLVM/SPIRV Translator // diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index 4a42173..85f4bb9 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -1,1870 +1,1870 @@ -//===- SPIRVWriter.cpp - Converts LLVM to SPIR-V ----------------*- C++ -*-===//
-//
-// The LLVM/SPIR-V 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file implements conversion of LLVM intermediate language to SPIR-V
-/// binary.
-///
-//===----------------------------------------------------------------------===//
-
-#include "SPIRVModule.h"
-#include "SPIRVEnum.h"
-#include "SPIRVEntry.h"
-#include "SPIRVType.h"
-#include "SPIRVValue.h"
-#include "SPIRVFunction.h"
-#include "SPIRVBasicBlock.h"
-#include "SPIRVInstruction.h"
-#include "SPIRVExtInst.h"
-#include "SPIRVUtil.h"
-#include "SPIRVInternal.h"
-#include "SPIRVMDWalker.h"
-#include "OCLTypeToSPIRV.h"
-#include "OCLUtil.h"
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SetVector.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Bitcode/BitcodeWriter.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/DebugInfo.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/InstrTypes.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Operator.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/IR/LegacyPassManager.h"
-#include "llvm/Pass.h"
-#include "llvm/PassSupport.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Transforms/IPO.h"
-
-#include <iostream>
-#include <list>
-#include <memory>
-#include <set>
-#include <sstream>
-#include <vector>
-#include <functional>
-#include <cstdlib>
-
-#define DEBUG_TYPE "spirv"
-
-using namespace llvm;
-using namespace SPIRV;
-using namespace OCLUtil;
-
-namespace llvm {
- FunctionPass *createPromoteMemoryToRegisterPass();
-}
-
-namespace SPIRV{
-
-cl::opt<bool> SPIRVMemToReg("spirv-mem2reg", cl::init(true),
- cl::desc("LLVM/SPIR-V translation enable mem2reg"));
-
-
-static void
-foreachKernelArgMD(MDNode *MD, SPIRVFunction *BF,
- std::function<void(const std::string& Str,
- SPIRVFunctionParameter *BA)>Func) {
- for (unsigned I = 1, E = MD->getNumOperands(); I != E; ++I) {
- SPIRVFunctionParameter *BA = BF->getArgument(I-1);
- Func(getMDOperandAsString(MD, I), BA);
- }
-}
-
-/// Information for translating OCL builtin.
-struct OCLBuiltinSPIRVTransInfo {
- std::string UniqName;
- /// Postprocessor of operands
- std::function<void(std::vector<SPIRVWord>&)> PostProc;
- OCLBuiltinSPIRVTransInfo(){
- PostProc = [](std::vector<SPIRVWord>&){};
- }
-};
-
-class LLVMToSPIRVDbgTran {
-public:
- LLVMToSPIRVDbgTran(Module *TM = nullptr, SPIRVModule *TBM = nullptr)
- :BM(TBM), M(TM){
- }
-
- void setModule(Module *Mod) { M = Mod;}
- void setSPIRVModule(SPIRVModule *SMod) { BM = SMod;}
-
- void transDbgInfo(Value *V, SPIRVValue *BV) {
- if (auto I = dyn_cast<Instruction>(V)) {
- auto DL = I->getDebugLoc();
- if (DL) {
- auto File = BM->getString(DL->getFilename().str());
- BM->addLine(BV, File->getId(), DL->getLine(), DL->getColumn());
- }
- } else if (auto F = dyn_cast<Function>(V)) {
- if (auto DIS = F->getSubprogram()) {
- auto File = BM->getString(DIS->getFilename().str());
- BM->addLine(BV, File->getId(), DIS->getLine(), 0);
- }
- }
- }
-
-private:
- SPIRVModule *BM;
- Module *M;
-};
-
-class LLVMToSPIRV: public ModulePass {
-public:
- LLVMToSPIRV(SPIRVModule *SMod = nullptr)
- : ModulePass(ID),
- M(nullptr),
- Ctx(nullptr),
- BM(SMod),
- ExtSetId(SPIRVID_INVALID),
- SrcLang(0),
- SrcLangVer(0),
- DbgTran(nullptr, SMod){
- }
-
- virtual StringRef getPassName() const {
- return "LLVMToSPIRV";
- }
-
- bool runOnModule(Module &Mod) override {
- M = &Mod;
- Ctx = &M->getContext();
- DbgTran.setModule(M);
- assert(BM && "SPIR-V module not initialized");
- translate();
- return true;
- }
-
- void getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<OCLTypeToSPIRV>();
- }
-
- static char ID;
-
- SPIRVType *transType(Type *T);
- SPIRVType *transSPIRVOpaqueType(Type *T);
-
- SPIRVValue *getTranslatedValue(Value *) const;
-
- // Translation functions
- bool transAddressingMode();
- bool transAlign(Value *V, SPIRVValue *BV);
- std::vector<SPIRVValue *> transArguments(CallInst *, SPIRVBasicBlock *);
- std::vector<SPIRVWord> transArguments(CallInst *, SPIRVBasicBlock *,
- SPIRVEntry *);
- bool transSourceLanguage();
- bool transExtension();
- bool transBuiltinSet();
- SPIRVValue *transIntrinsicInst(IntrinsicInst *Intrinsic, SPIRVBasicBlock *BB);
- SPIRVValue *transCallInst(CallInst *Call, SPIRVBasicBlock *BB);
- bool transDecoration(Value *V, SPIRVValue *BV);
- SPIRVWord transFunctionControlMask(CallInst *);
- SPIRVWord transFunctionControlMask(Function *);
- SPIRVFunction *transFunctionDecl(Function *F);
- bool transGlobalVariables();
-
- Op transBoolOpCode(SPIRVValue *Opn, Op OC);
- // Translate LLVM module to SPIR-V module.
- // Returns true if succeeds.
- bool translate();
- bool transExecutionMode();
- SPIRVValue *transConstant(Value *V);
- SPIRVValue *transValue(Value *V, SPIRVBasicBlock *BB,
- bool CreateForward = true);
- SPIRVValue *transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB,
- bool CreateForward = true);
-
- typedef DenseMap<Type *, SPIRVType *> LLVMToSPIRVTypeMap;
- typedef DenseMap<Value *, SPIRVValue *> LLVMToSPIRVValueMap;
-private:
- Module *M;
- LLVMContext *Ctx;
- SPIRVModule *BM;
- LLVMToSPIRVTypeMap TypeMap;
- LLVMToSPIRVValueMap ValueMap;
- //ToDo: support multiple builtin sets. Currently assume one builtin set.
- SPIRVId ExtSetId;
- SPIRVWord SrcLang;
- SPIRVWord SrcLangVer;
- LLVMToSPIRVDbgTran DbgTran;
-
- SPIRVType *mapType(Type *T, SPIRVType *BT) {
- TypeMap[T] = BT;
- SPIRVDBG(dbgs() << "[mapType] " << *T << " => ";
- spvdbgs() << *BT << '\n');
- return BT;
- }
-
- SPIRVValue *mapValue(Value *V, SPIRVValue *BV) {
- auto Loc = ValueMap.find(V);
- if (Loc != ValueMap.end()) {
- if (Loc->second == BV)
- return BV;
- assert (Loc->second->isForward() &&
- "LLVM Value is mapped to different SPIRV Values");
- auto Forward = static_cast<SPIRVForward *>(Loc->second);
- BM->replaceForward(Forward, BV);
- }
- ValueMap[V] = BV;
- SPIRVDBG(dbgs() << "[mapValue] " << *V << " => ";
- spvdbgs() << *BV << "\n");
- return BV;
- }
-
- SPIRVType *getSPIRVType(Type *T) {
- return TypeMap[T];
- }
-
- SPIRVValue *getSPIRVValue(Value *V) {
- return ValueMap[V];
- }
-
- SPIRVErrorLog &getErrorLog() {
- return BM->getErrorLog();
- }
-
- llvm::IntegerType* getSizetType();
- std::vector<SPIRVValue*> transValue(const std::vector<Value *> &Values,
- SPIRVBasicBlock* BB);
- std::vector<SPIRVWord> transValue(const std::vector<Value *> &Values,
- SPIRVBasicBlock* BB, SPIRVEntry *Entry);
-
- SPIRVInstruction* transBinaryInst(BinaryOperator* B, SPIRVBasicBlock* BB);
- SPIRVInstruction* transCmpInst(CmpInst* Cmp, SPIRVBasicBlock* BB);
- SPIRVInstruction* transLifetimeIntrinsicInst(Op OC, IntrinsicInst *Intrinsic, SPIRVBasicBlock *BB);
-
- void dumpUsers(Value *V);
-
- template<class ExtInstKind>
- bool oclGetExtInstIndex(const std::string &MangledName,
- const std::string& DemangledName, SPIRVWord* EntryPoint);
- void oclGetMutatedArgumentTypesByBuiltin(llvm::FunctionType* FT,
- std::map<unsigned, Type*>& ChangedType, Function* F);
-
- bool isBuiltinTransToInst(Function *F);
- bool isBuiltinTransToExtInst(Function *F,
- SPIRVExtInstSetKind *BuiltinSet = nullptr,
- SPIRVWord *EntryPoint = nullptr,
- SmallVectorImpl<std::string> *Dec = nullptr);
- bool oclIsKernel(Function *F);
-
- bool transOCLKernelMetadata();
-
- SPIRVInstruction *transBuiltinToInst(const std::string& DemangledName,
- const std::string &MangledName, CallInst* CI, SPIRVBasicBlock* BB);
- SPIRVInstruction *transBuiltinToInstWithoutDecoration(Op OC,
- CallInst* CI, SPIRVBasicBlock* BB);
- void mutateFuncArgType(const std::map<unsigned, Type*>& ChangedType,
- Function* F);
-
- SPIRVValue *transSpcvCast(CallInst* CI, SPIRVBasicBlock *BB);
- SPIRVValue *oclTransSpvcCastSampler(CallInst* CI, SPIRVBasicBlock *BB);
-
- SPIRV::SPIRVInstruction* transUnaryInst(UnaryInstruction* U,
- SPIRVBasicBlock* BB);
-
- /// Add a 32 bit integer constant.
- /// \return Id of the constant.
- SPIRVId addInt32(int);
- void transFunction(Function *I);
- SPIRV::SPIRVLinkageTypeKind transLinkageType(const GlobalValue* GV);
-};
-
-
-SPIRVValue *
-LLVMToSPIRV::getTranslatedValue(Value *V) const {
- auto Loc = ValueMap.find(V);
- if (Loc != ValueMap.end())
- return Loc->second;
- return nullptr;
-}
-
-bool
-LLVMToSPIRV::oclIsKernel(Function *F) {
- if (F->getCallingConv() == CallingConv::SPIR_KERNEL)
- return true;
- return false;
-}
-
-bool
-LLVMToSPIRV::isBuiltinTransToInst(Function *F) {
- std::string DemangledName;
- if (!oclIsBuiltin(F->getName(), &DemangledName) &&
- !isDecoratedSPIRVFunc(F, &DemangledName))
- return false;
- SPIRVDBG(spvdbgs() << "CallInst: demangled name: " << DemangledName << '\n');
- return getSPIRVFuncOC(DemangledName) != OpNop;
-}
-
-bool
-LLVMToSPIRV::isBuiltinTransToExtInst(Function *F,
- SPIRVExtInstSetKind *ExtSet,
- SPIRVWord *ExtOp,
- SmallVectorImpl<std::string> *Dec) {
- std::string OrigName = F->getName();
- std::string DemangledName;
- if (!oclIsBuiltin(OrigName, &DemangledName))
- return false;
- DEBUG(dbgs() << "[oclIsBuiltinTransToExtInst] CallInst: demangled name: "
- << DemangledName << '\n');
- StringRef S = DemangledName;
- if (!S.startswith(kSPIRVName::Prefix))
- return false;
- S = S.drop_front(strlen(kSPIRVName::Prefix));
- auto Loc = S.find(kSPIRVPostfix::Divider);
- auto ExtSetName = S.substr(0, Loc);
- SPIRVExtInstSetKind Set = SPIRVEIS_Count;
- if (!SPIRVExtSetShortNameMap::rfind(ExtSetName, &Set))
- return false;
- assert(Set == BM->getBuiltinSet(ExtSetId) &&
- "Invalid extended instruction set");
- assert(Set == SPIRVEIS_OpenCL && "Unsupported extended instruction set");
-
- auto ExtOpName = S.substr(Loc + 1);
- auto Splited = ExtOpName.split(kSPIRVPostfix::ExtDivider);
- OCLExtOpKind EOC;
- if (!OCLExtOpMap::rfind(Splited.first, &EOC))
- return false;
-
- if (ExtSet)
- *ExtSet = Set;
- if (ExtOp)
- *ExtOp = EOC;
- if (Dec) {
- SmallVector<StringRef, 2> P;
- Splited.second.split(P, kSPIRVPostfix::Divider);
- for (auto &I:P)
- Dec->push_back(I.str());
- }
- return true;
-}
-
-/// Decode SPIR-V type name in the format spirv.{TypeName}._{Postfixes}
-/// where Postfixes are strings separated by underscores.
-/// \return TypeName.
-/// \param Ops contains the integers decoded from postfixes.
-static std::string
- decodeSPIRVTypeName(StringRef Name,
- SmallVectorImpl<std::string>& Strs) {
- SmallVector<StringRef, 4> SubStrs;
- const char Delim[] = { kSPIRVTypeName::Delimiter, 0 };
- Name.split(SubStrs, Delim, -1, true);
- assert(SubStrs.size() >= 2 && "Invalid SPIRV type name");
- assert(SubStrs[0] == kSPIRVTypeName::Prefix && "Invalid prefix");
- assert((SubStrs.size() == 2 || !SubStrs[2].empty()) && "Invalid postfix");
-
- if (SubStrs.size() > 2) {
- const char PostDelim[] = { kSPIRVTypeName::PostfixDelim, 0 };
- SmallVector<StringRef, 4> Postfixes;
- SubStrs[2].split(Postfixes, PostDelim, -1, true);
- assert(Postfixes.size() > 1 && Postfixes[0].empty() && "Invalid postfix");
- for (unsigned I = 1, E = Postfixes.size(); I != E; ++I)
- Strs.push_back(std::string(Postfixes[I]).c_str());
- }
- return SubStrs[1].str();
-}
-
-static bool recursiveType(const StructType *ST, const Type *Ty) {
- SmallPtrSet<const StructType *, 4> Seen;
-
- std::function<bool(const Type *Ty)> Run = [&](const Type *Ty) {
- if (!isa<CompositeType>(Ty) && !Ty->isPointerTy())
- return false;
-
- if (auto *StructTy = dyn_cast<StructType>(Ty)) {
- if (StructTy == ST)
- return true;
-
- if (Seen.count(StructTy))
- return false;
-
- Seen.insert(StructTy);
-
- return find_if(StructTy->element_begin(), StructTy->element_end(), Run) !=
- StructTy->element_end();
- }
-
- if (auto *PtrTy = dyn_cast<PointerType>(Ty))
- return Run(PtrTy->getPointerElementType());
-
- if (auto *ArrayTy = dyn_cast<ArrayType>(Ty))
- return Run(ArrayTy->getArrayElementType());
-
- return false;
- };
-
- return Run(Ty);
-}
-
-SPIRVType *
-LLVMToSPIRV::transType(Type *T) {
- LLVMToSPIRVTypeMap::iterator Loc = TypeMap.find(T);
- if (Loc != TypeMap.end())
- return Loc->second;
-
- SPIRVDBG(dbgs() << "[transType] " << *T << '\n');
- if (T->isVoidTy())
- return mapType(T, BM->addVoidType());
-
- if (T->isIntegerTy(1))
- return mapType(T, BM->addBoolType());
-
- if (T->isIntegerTy())
- return mapType(T, BM->addIntegerType(T->getIntegerBitWidth()));
-
- if (T->isFloatingPointTy())
- return mapType(T, BM->addFloatType(T->getPrimitiveSizeInBits()));
-
- // A pointer to image or pipe type in LLVM is translated to a SPIRV
- // sampler or pipe type.
- if (T->isPointerTy()) {
- auto ET = T->getPointerElementType();
- assert(!ET->isFunctionTy() && "Function pointer type is not allowed");
- auto ST = dyn_cast<StructType>(ET);
- auto AddrSpc = T->getPointerAddressSpace();
- if (ST && !ST->isSized()) {
- Op OpCode;
- StringRef STName = ST->getName();
- // Workaround for non-conformant SPIR binary
- if (STName == "struct._event_t") {
- STName = kSPR2TypeName::Event;
- ST->setName(STName);
- }
- assert (!STName.startswith(kSPR2TypeName::Pipe) &&
- "OpenCL type names should be translated to SPIR-V type names");
- // ToDo: For SPIR1.2/2.0 there may still be load/store or bitcast
- // instructions using opencl.* type names. We need to handle these
- // type names until they are all mapped or FE generates SPIR-V type
- // names.
- if (STName.find(kSPR2TypeName::Pipe) == 0) {
- assert(AddrSpc == SPIRAS_Global);
- SmallVector<StringRef, 4> SubStrs;
- const char Delims[] = {kSPR2TypeName::Delimiter, 0};
- STName.split(SubStrs, Delims);
- std::string Acc = kAccessQualName::ReadOnly;
- if (SubStrs.size() > 2) {
- Acc = SubStrs[2];
- }
- auto PipeT = BM->addPipeType();
- PipeT->setPipeAcessQualifier(SPIRSPIRVAccessQualifierMap::map(Acc));
- return mapType(T, PipeT);
- } else if (STName.find(kSPR2TypeName::ImagePrefix) == 0) {
- assert(AddrSpc == SPIRAS_Global);
- auto SPIRVImageTy = getSPIRVImageTypeFromOCL(M, T);
- return mapType(T, transSPIRVOpaqueType(SPIRVImageTy));
- } else if (STName.startswith(kSPIRVTypeName::PrefixAndDelim))
- return transSPIRVOpaqueType(T);
- else if (OCLOpaqueTypeOpCodeMap::find(STName, &OpCode)) {
- switch (OpCode) {
- default:
- return mapType(T, BM->addOpaqueGenericType(OpCode));
- case OpTypePipe:
- return mapType(T, BM->addPipeType());
- case OpTypeDeviceEvent:
- return mapType(T, BM->addDeviceEventType());
- case OpTypeQueue:
- return mapType(T, BM->addQueueType());
- }
- } else if (isPointerToOpaqueStructType(T)) {
- return mapType(T, BM->addPointerType(SPIRSPIRVAddrSpaceMap::map(
- static_cast<SPIRAddressSpace>(AddrSpc)),
- transType(ET)));
- }
- } else {
- return mapType(T, BM->addPointerType(SPIRSPIRVAddrSpaceMap::map(
- static_cast<SPIRAddressSpace>(AddrSpc)),
- transType(ET)));
- }
- }
-
- if (T->isVectorTy())
- return mapType(T, BM->addVectorType(transType(T->getVectorElementType()),
- T->getVectorNumElements()));
-
- if (T->isArrayTy())
- return mapType(T, BM->addArrayType(transType(T->getArrayElementType()),
- static_cast<SPIRVConstant*>(transValue(ConstantInt::get(getSizetType(),
- T->getArrayNumElements(), false), nullptr))));
-
- if (T->isStructTy() && !T->isSized()) {
- auto ST = dyn_cast<StructType>(T);
+//===- SPIRVWriter.cpp - Converts LLVM to SPIR-V ----------------*- C++ -*-===// +// +// The LLVM/SPIR-V 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file implements conversion of LLVM intermediate language to SPIR-V +/// binary. +/// +//===----------------------------------------------------------------------===// + +#include "SPIRVModule.h" +#include "SPIRVEnum.h" +#include "SPIRVEntry.h" +#include "SPIRVType.h" +#include "SPIRVValue.h" +#include "SPIRVFunction.h" +#include "SPIRVBasicBlock.h" +#include "SPIRVInstruction.h" +#include "SPIRVExtInst.h" +#include "SPIRVUtil.h" +#include "SPIRVInternal.h" +#include "SPIRVMDWalker.h" +#include "OCLTypeToSPIRV.h" +#include "OCLUtil.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/Verifier.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/Pass.h" +#include "llvm/PassSupport.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Transforms/IPO.h" + +#include <iostream> +#include <list> +#include <memory> +#include <set> +#include <sstream> +#include <vector> +#include <functional> +#include <cstdlib> + +#define DEBUG_TYPE "spirv" + +using namespace llvm; +using namespace SPIRV; +using namespace OCLUtil; + +namespace llvm { + FunctionPass *createPromoteMemoryToRegisterPass(); +} + +namespace SPIRV{ + +cl::opt<bool> SPIRVMemToReg("spirv-mem2reg", cl::init(true), + cl::desc("LLVM/SPIR-V translation enable mem2reg")); + + +static void +foreachKernelArgMD(MDNode *MD, SPIRVFunction *BF, + std::function<void(const std::string& Str, + SPIRVFunctionParameter *BA)>Func) { + for (unsigned I = 1, E = MD->getNumOperands(); I != E; ++I) { + SPIRVFunctionParameter *BA = BF->getArgument(I-1); + Func(getMDOperandAsString(MD, I), BA); + } +} + +/// Information for translating OCL builtin. +struct OCLBuiltinSPIRVTransInfo { + std::string UniqName; + /// Postprocessor of operands + std::function<void(std::vector<SPIRVWord>&)> PostProc; + OCLBuiltinSPIRVTransInfo(){ + PostProc = [](std::vector<SPIRVWord>&){}; + } +}; + +class LLVMToSPIRVDbgTran { +public: + LLVMToSPIRVDbgTran(Module *TM = nullptr, SPIRVModule *TBM = nullptr) + :BM(TBM), M(TM){ + } + + void setModule(Module *Mod) { M = Mod;} + void setSPIRVModule(SPIRVModule *SMod) { BM = SMod;} + + void transDbgInfo(Value *V, SPIRVValue *BV) { + if (auto I = dyn_cast<Instruction>(V)) { + auto DL = I->getDebugLoc(); + if (DL) { + auto File = BM->getString(DL->getFilename().str()); + BM->addLine(BV, File->getId(), DL->getLine(), DL->getColumn()); + } + } else if (auto F = dyn_cast<Function>(V)) { + if (auto DIS = F->getSubprogram()) { + auto File = BM->getString(DIS->getFilename().str()); + BM->addLine(BV, File->getId(), DIS->getLine(), 0); + } + } + } + +private: + SPIRVModule *BM; + Module *M; +}; + +class LLVMToSPIRV: public ModulePass { +public: + LLVMToSPIRV(SPIRVModule *SMod = nullptr) + : ModulePass(ID), + M(nullptr), + Ctx(nullptr), + BM(SMod), + ExtSetId(SPIRVID_INVALID), + SrcLang(0), + SrcLangVer(0), + DbgTran(nullptr, SMod){ + } + + virtual StringRef getPassName() const { + return "LLVMToSPIRV"; + } + + bool runOnModule(Module &Mod) override { + M = &Mod; + Ctx = &M->getContext(); + DbgTran.setModule(M); + assert(BM && "SPIR-V module not initialized"); + translate(); + return true; + } + + void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<OCLTypeToSPIRV>(); + } + + static char ID; + + SPIRVType *transType(Type *T); + SPIRVType *transSPIRVOpaqueType(Type *T); + + SPIRVValue *getTranslatedValue(Value *) const; + + // Translation functions + bool transAddressingMode(); + bool transAlign(Value *V, SPIRVValue *BV); + std::vector<SPIRVValue *> transArguments(CallInst *, SPIRVBasicBlock *); + std::vector<SPIRVWord> transArguments(CallInst *, SPIRVBasicBlock *, + SPIRVEntry *); + bool transSourceLanguage(); + bool transExtension(); + bool transBuiltinSet(); + SPIRVValue *transIntrinsicInst(IntrinsicInst *Intrinsic, SPIRVBasicBlock *BB); + SPIRVValue *transCallInst(CallInst *Call, SPIRVBasicBlock *BB); + bool transDecoration(Value *V, SPIRVValue *BV); + SPIRVWord transFunctionControlMask(CallInst *); + SPIRVWord transFunctionControlMask(Function *); + SPIRVFunction *transFunctionDecl(Function *F); + bool transGlobalVariables(); + + Op transBoolOpCode(SPIRVValue *Opn, Op OC); + // Translate LLVM module to SPIR-V module. + // Returns true if succeeds. + bool translate(); + bool transExecutionMode(); + SPIRVValue *transConstant(Value *V); + SPIRVValue *transValue(Value *V, SPIRVBasicBlock *BB, + bool CreateForward = true); + SPIRVValue *transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, + bool CreateForward = true); + + typedef DenseMap<Type *, SPIRVType *> LLVMToSPIRVTypeMap; + typedef DenseMap<Value *, SPIRVValue *> LLVMToSPIRVValueMap; +private: + Module *M; + LLVMContext *Ctx; + SPIRVModule *BM; + LLVMToSPIRVTypeMap TypeMap; + LLVMToSPIRVValueMap ValueMap; + //ToDo: support multiple builtin sets. Currently assume one builtin set. + SPIRVId ExtSetId; + SPIRVWord SrcLang; + SPIRVWord SrcLangVer; + LLVMToSPIRVDbgTran DbgTran; + + SPIRVType *mapType(Type *T, SPIRVType *BT) { + TypeMap[T] = BT; + SPIRVDBG(dbgs() << "[mapType] " << *T << " => "; + spvdbgs() << *BT << '\n'); + return BT; + } + + SPIRVValue *mapValue(Value *V, SPIRVValue *BV) { + auto Loc = ValueMap.find(V); + if (Loc != ValueMap.end()) { + if (Loc->second == BV) + return BV; + assert (Loc->second->isForward() && + "LLVM Value is mapped to different SPIRV Values"); + auto Forward = static_cast<SPIRVForward *>(Loc->second); + BM->replaceForward(Forward, BV); + } + ValueMap[V] = BV; + SPIRVDBG(dbgs() << "[mapValue] " << *V << " => "; + spvdbgs() << *BV << "\n"); + return BV; + } + + SPIRVType *getSPIRVType(Type *T) { + return TypeMap[T]; + } + + SPIRVValue *getSPIRVValue(Value *V) { + return ValueMap[V]; + } + + SPIRVErrorLog &getErrorLog() { + return BM->getErrorLog(); + } + + llvm::IntegerType* getSizetType(); + std::vector<SPIRVValue*> transValue(const std::vector<Value *> &Values, + SPIRVBasicBlock* BB); + std::vector<SPIRVWord> transValue(const std::vector<Value *> &Values, + SPIRVBasicBlock* BB, SPIRVEntry *Entry); + + SPIRVInstruction* transBinaryInst(BinaryOperator* B, SPIRVBasicBlock* BB); + SPIRVInstruction* transCmpInst(CmpInst* Cmp, SPIRVBasicBlock* BB); + SPIRVInstruction* transLifetimeIntrinsicInst(Op OC, IntrinsicInst *Intrinsic, SPIRVBasicBlock *BB); + + void dumpUsers(Value *V); + + template<class ExtInstKind> + bool oclGetExtInstIndex(const std::string &MangledName, + const std::string& DemangledName, SPIRVWord* EntryPoint); + void oclGetMutatedArgumentTypesByBuiltin(llvm::FunctionType* FT, + std::map<unsigned, Type*>& ChangedType, Function* F); + + bool isBuiltinTransToInst(Function *F); + bool isBuiltinTransToExtInst(Function *F, + SPIRVExtInstSetKind *BuiltinSet = nullptr, + SPIRVWord *EntryPoint = nullptr, + SmallVectorImpl<std::string> *Dec = nullptr); + bool oclIsKernel(Function *F); + + bool transOCLKernelMetadata(); + + SPIRVInstruction *transBuiltinToInst(const std::string& DemangledName, + const std::string &MangledName, CallInst* CI, SPIRVBasicBlock* BB); + SPIRVInstruction *transBuiltinToInstWithoutDecoration(Op OC, + CallInst* CI, SPIRVBasicBlock* BB); + void mutateFuncArgType(const std::map<unsigned, Type*>& ChangedType, + Function* F); + + SPIRVValue *transSpcvCast(CallInst* CI, SPIRVBasicBlock *BB); + SPIRVValue *oclTransSpvcCastSampler(CallInst* CI, SPIRVBasicBlock *BB); + + SPIRV::SPIRVInstruction* transUnaryInst(UnaryInstruction* U, + SPIRVBasicBlock* BB); + + /// Add a 32 bit integer constant. + /// \return Id of the constant. + SPIRVId addInt32(int); + void transFunction(Function *I); + SPIRV::SPIRVLinkageTypeKind transLinkageType(const GlobalValue* GV); +}; + + +SPIRVValue * +LLVMToSPIRV::getTranslatedValue(Value *V) const { + auto Loc = ValueMap.find(V); + if (Loc != ValueMap.end()) + return Loc->second; + return nullptr; +} + +bool +LLVMToSPIRV::oclIsKernel(Function *F) { + if (F->getCallingConv() == CallingConv::SPIR_KERNEL) + return true; + return false; +} + +bool +LLVMToSPIRV::isBuiltinTransToInst(Function *F) { + std::string DemangledName; + if (!oclIsBuiltin(F->getName(), &DemangledName) && + !isDecoratedSPIRVFunc(F, &DemangledName)) + return false; + SPIRVDBG(spvdbgs() << "CallInst: demangled name: " << DemangledName << '\n'); + return getSPIRVFuncOC(DemangledName) != OpNop; +} + +bool +LLVMToSPIRV::isBuiltinTransToExtInst(Function *F, + SPIRVExtInstSetKind *ExtSet, + SPIRVWord *ExtOp, + SmallVectorImpl<std::string> *Dec) { + std::string OrigName = F->getName(); + std::string DemangledName; + if (!oclIsBuiltin(OrigName, &DemangledName)) + return false; + DEBUG(dbgs() << "[oclIsBuiltinTransToExtInst] CallInst: demangled name: " + << DemangledName << '\n'); + StringRef S = DemangledName; + if (!S.startswith(kSPIRVName::Prefix)) + return false; + S = S.drop_front(strlen(kSPIRVName::Prefix)); + auto Loc = S.find(kSPIRVPostfix::Divider); + auto ExtSetName = S.substr(0, Loc); + SPIRVExtInstSetKind Set = SPIRVEIS_Count; + if (!SPIRVExtSetShortNameMap::rfind(ExtSetName, &Set)) + return false; + assert(Set == BM->getBuiltinSet(ExtSetId) && + "Invalid extended instruction set"); + assert(Set == SPIRVEIS_OpenCL && "Unsupported extended instruction set"); + + auto ExtOpName = S.substr(Loc + 1); + auto Splited = ExtOpName.split(kSPIRVPostfix::ExtDivider); + OCLExtOpKind EOC; + if (!OCLExtOpMap::rfind(Splited.first, &EOC)) + return false; + + if (ExtSet) + *ExtSet = Set; + if (ExtOp) + *ExtOp = EOC; + if (Dec) { + SmallVector<StringRef, 2> P; + Splited.second.split(P, kSPIRVPostfix::Divider); + for (auto &I:P) + Dec->push_back(I.str()); + } + return true; +} + +/// Decode SPIR-V type name in the format spirv.{TypeName}._{Postfixes} +/// where Postfixes are strings separated by underscores. +/// \return TypeName. +/// \param Ops contains the integers decoded from postfixes. +static std::string + decodeSPIRVTypeName(StringRef Name, + SmallVectorImpl<std::string>& Strs) { + SmallVector<StringRef, 4> SubStrs; + const char Delim[] = { kSPIRVTypeName::Delimiter, 0 }; + Name.split(SubStrs, Delim, -1, true); + assert(SubStrs.size() >= 2 && "Invalid SPIRV type name"); + assert(SubStrs[0] == kSPIRVTypeName::Prefix && "Invalid prefix"); + assert((SubStrs.size() == 2 || !SubStrs[2].empty()) && "Invalid postfix"); + + if (SubStrs.size() > 2) { + const char PostDelim[] = { kSPIRVTypeName::PostfixDelim, 0 }; + SmallVector<StringRef, 4> Postfixes; + SubStrs[2].split(Postfixes, PostDelim, -1, true); + assert(Postfixes.size() > 1 && Postfixes[0].empty() && "Invalid postfix"); + for (unsigned I = 1, E = Postfixes.size(); I != E; ++I) + Strs.push_back(std::string(Postfixes[I]).c_str()); + } + return SubStrs[1].str(); +} + +static bool recursiveType(const StructType *ST, const Type *Ty) { + SmallPtrSet<const StructType *, 4> Seen; + + std::function<bool(const Type *Ty)> Run = [&](const Type *Ty) { + if (!isa<CompositeType>(Ty) && !Ty->isPointerTy()) + return false; + + if (auto *StructTy = dyn_cast<StructType>(Ty)) { + if (StructTy == ST) + return true; + + if (Seen.count(StructTy)) + return false; + + Seen.insert(StructTy); + + return find_if(StructTy->element_begin(), StructTy->element_end(), Run) != + StructTy->element_end(); + } + + if (auto *PtrTy = dyn_cast<PointerType>(Ty)) + return Run(PtrTy->getPointerElementType()); + + if (auto *ArrayTy = dyn_cast<ArrayType>(Ty)) + return Run(ArrayTy->getArrayElementType()); + + return false; + }; + + return Run(Ty); +} + +SPIRVType * +LLVMToSPIRV::transType(Type *T) { + LLVMToSPIRVTypeMap::iterator Loc = TypeMap.find(T); + if (Loc != TypeMap.end()) + return Loc->second; + + SPIRVDBG(dbgs() << "[transType] " << *T << '\n'); + if (T->isVoidTy()) + return mapType(T, BM->addVoidType()); + + if (T->isIntegerTy(1)) + return mapType(T, BM->addBoolType()); + + if (T->isIntegerTy()) + return mapType(T, BM->addIntegerType(T->getIntegerBitWidth())); + + if (T->isFloatingPointTy()) + return mapType(T, BM->addFloatType(T->getPrimitiveSizeInBits())); + + // A pointer to image or pipe type in LLVM is translated to a SPIRV + // sampler or pipe type. + if (T->isPointerTy()) { + auto ET = T->getPointerElementType(); + assert(!ET->isFunctionTy() && "Function pointer type is not allowed"); + auto ST = dyn_cast<StructType>(ET); + auto AddrSpc = T->getPointerAddressSpace(); + if (ST && !ST->isSized()) { + Op OpCode; + StringRef STName = ST->getName(); + // Workaround for non-conformant SPIR binary + if (STName == "struct._event_t") { + STName = kSPR2TypeName::Event; + ST->setName(STName); + } + assert (!STName.startswith(kSPR2TypeName::Pipe) && + "OpenCL type names should be translated to SPIR-V type names"); + // ToDo: For SPIR1.2/2.0 there may still be load/store or bitcast + // instructions using opencl.* type names. We need to handle these + // type names until they are all mapped or FE generates SPIR-V type + // names. + if (STName.find(kSPR2TypeName::Pipe) == 0) { + assert(AddrSpc == SPIRAS_Global); + SmallVector<StringRef, 4> SubStrs; + const char Delims[] = {kSPR2TypeName::Delimiter, 0}; + STName.split(SubStrs, Delims); + std::string Acc = kAccessQualName::ReadOnly; + if (SubStrs.size() > 2) { + Acc = SubStrs[2]; + } + auto PipeT = BM->addPipeType(); + PipeT->setPipeAcessQualifier(SPIRSPIRVAccessQualifierMap::map(Acc)); + return mapType(T, PipeT); + } else if (STName.find(kSPR2TypeName::ImagePrefix) == 0) { + assert(AddrSpc == SPIRAS_Global); + auto SPIRVImageTy = getSPIRVImageTypeFromOCL(M, T); + return mapType(T, transSPIRVOpaqueType(SPIRVImageTy)); + } else if (STName.startswith(kSPIRVTypeName::PrefixAndDelim)) + return transSPIRVOpaqueType(T); + else if (OCLOpaqueTypeOpCodeMap::find(STName, &OpCode)) { + switch (OpCode) { + default: + return mapType(T, BM->addOpaqueGenericType(OpCode)); + case OpTypePipe: + return mapType(T, BM->addPipeType()); + case OpTypeDeviceEvent: + return mapType(T, BM->addDeviceEventType()); + case OpTypeQueue: + return mapType(T, BM->addQueueType()); + } + } else if (isPointerToOpaqueStructType(T)) { + return mapType(T, BM->addPointerType(SPIRSPIRVAddrSpaceMap::map( + static_cast<SPIRAddressSpace>(AddrSpc)), + transType(ET))); + } + } else { + return mapType(T, BM->addPointerType(SPIRSPIRVAddrSpaceMap::map( + static_cast<SPIRAddressSpace>(AddrSpc)), + transType(ET))); + } + } + + if (T->isVectorTy()) + return mapType(T, BM->addVectorType(transType(T->getVectorElementType()), + T->getVectorNumElements())); + + if (T->isArrayTy()) + return mapType(T, BM->addArrayType(transType(T->getArrayElementType()), + static_cast<SPIRVConstant*>(transValue(ConstantInt::get(getSizetType(), + T->getArrayNumElements(), false), nullptr)))); + + if (T->isStructTy() && !T->isSized()) { + auto ST = dyn_cast<StructType>(T); (void)ST; // Silence warning - assert(!ST->getName().startswith(kSPR2TypeName::Pipe));
- assert(!ST->getName().startswith(kSPR2TypeName::ImagePrefix));
- return mapType(T, BM->addOpaqueType(T->getStructName()));
- }
-
- if (auto ST = dyn_cast<StructType>(T)) {
- assert(ST->isSized());
-
- std::string Name;
- if (ST->hasName())
- Name = ST->getName();
-
- if(Name == getSPIRVTypeName(kSPIRVTypeName::ConstantSampler))
- return transType(getSamplerType(M));
- if (Name == getSPIRVTypeName(kSPIRVTypeName::ConstantPipeStorage))
- return transType(getPipeStorageType(M));
-
- auto *Struct = BM->openStructType(T->getStructNumElements(), Name);
- mapType(T, Struct);
-
- SmallVector<unsigned, 4> ForwardRefs;
-
- for (unsigned I = 0, E = T->getStructNumElements(); I != E; ++I) {
- auto *ElemTy = ST->getElementType(I);
- if ((isa<CompositeType>(ElemTy) || isa<PointerType>(ElemTy)) && recursiveType(ST, ElemTy))
- ForwardRefs.push_back(I);
- else
- Struct->setMemberType(I, transType(ST->getElementType(I)));
- }
-
- BM->closeStructType(Struct, ST->isPacked());
-
- for (auto I : ForwardRefs)
- Struct->setMemberType(I, transType(ST->getElementType(I)));
-
- return Struct;
- }
-
- if (FunctionType *FT = dyn_cast<FunctionType>(T)) {
- SPIRVType *RT = transType(FT->getReturnType());
- std::vector<SPIRVType *> PT;
- for (FunctionType::param_iterator I = FT->param_begin(),
- E = FT->param_end();
- I != E; ++I)
- PT.push_back(transType(*I));
- return mapType(T, BM->addFunctionType(RT, PT));
- }
-
- llvm_unreachable("Not implemented!");
- return 0;
-}
-
-SPIRVType *
-LLVMToSPIRV::transSPIRVOpaqueType(Type *T) {
- auto ET = T->getPointerElementType();
- auto ST = cast<StructType>(ET);
- auto STName = ST->getStructName();
- assert (STName.startswith(kSPIRVTypeName::PrefixAndDelim) &&
- "Invalid SPIR-V opaque type name");
- SmallVector<std::string, 8> Postfixes;
- auto TN = decodeSPIRVTypeName(STName, Postfixes);
- if (TN == kSPIRVTypeName::Pipe) {
- assert(T->getPointerAddressSpace() == SPIRAS_Global);
- assert(Postfixes.size() == 1 && "Invalid pipe type ops");
- auto PipeT = BM->addPipeType();
- PipeT->setPipeAcessQualifier(static_cast<spv::AccessQualifier>(
- atoi(Postfixes[0].c_str())));
- return mapType(T, PipeT);
- } else if (TN == kSPIRVTypeName::Image) {
- assert(T->getPointerAddressSpace() == SPIRAS_Global);
- // The sampled type needs to be translated through LLVM type to guarantee
- // uniqueness.
- auto SampledT = transType(getLLVMTypeForSPIRVImageSampledTypePostfix(
- Postfixes[0], *Ctx));
- SmallVector<int, 7> Ops;
- for (unsigned I = 1; I < 8; ++I)
- Ops.push_back(atoi(Postfixes[I].c_str()));
- SPIRVTypeImageDescriptor Desc(static_cast<SPIRVImageDimKind>(Ops[0]),
- Ops[1], Ops[2], Ops[3], Ops[4], Ops[5]);
- return mapType(T, BM->addImageType(SampledT, Desc,
- static_cast<spv::AccessQualifier>(Ops[6])));
- } else if (TN == kSPIRVTypeName::SampledImg) {
- return mapType(T, BM->addSampledImageType(
- static_cast<SPIRVTypeImage *>(
- transType(getSPIRVTypeByChangeBaseTypeName(M,
- T, kSPIRVTypeName::SampledImg,
- kSPIRVTypeName::Image)))));
- } else if(TN == kSPIRVTypeName::Sampler)
- return mapType(T, BM->addSamplerType());
- else if (TN == kSPIRVTypeName::DeviceEvent)
- return mapType(T, BM->addDeviceEventType());
- else if (TN == kSPIRVTypeName::Queue)
- return mapType(T, BM->addQueueType());
- else if (TN == kSPIRVTypeName::PipeStorage)
- return mapType(T, BM->addPipeStorageType());
- else
- return mapType(T, BM->addOpaqueGenericType(
- SPIRVOpaqueTypeOpCodeMap::map(TN)));
-}
-
-SPIRVFunction *
-LLVMToSPIRV::transFunctionDecl(Function *F) {
- if (auto BF = getTranslatedValue(F))
- return static_cast<SPIRVFunction *>(BF);
-
- if (F->isIntrinsic()) {
- // We should not translate LLVM intrinsics as a function
- assert(none_of(F->user_begin(), F->user_end(),
- [this](User *U){ return getTranslatedValue(U);}) &&
- "LLVM intrinsics shouldn't be called in SPIRV");
- return nullptr;
- }
-
- SPIRVTypeFunction *BFT = static_cast<SPIRVTypeFunction *>(transType(
- getAnalysis<OCLTypeToSPIRV>().getAdaptedType(F)));
- SPIRVFunction *BF = static_cast<SPIRVFunction *>(mapValue(F,
- BM->addFunction(BFT)));
- BF->setFunctionControlMask(transFunctionControlMask(F));
- if (F->hasName())
- BM->setName(BF, F->getName());
- if (oclIsKernel(F))
- BM->addEntryPoint(ExecutionModelKernel, BF->getId());
- else if (F->getLinkage() != GlobalValue::InternalLinkage)
- BF->setLinkageType(transLinkageType(F));
- auto Attrs = F->getAttributes();
- for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E;
- ++I) {
- auto ArgNo = I->getArgNo();
- SPIRVFunctionParameter *BA = BF->getArgument(ArgNo);
- if (I->hasName())
- BM->setName(BA, I->getName());
- if (I->hasByValAttr())
- BA->addAttr(FunctionParameterAttributeByVal);
- if (I->hasNoAliasAttr())
- BA->addAttr(FunctionParameterAttributeNoAlias);
- if (I->hasNoCaptureAttr())
- BA->addAttr(FunctionParameterAttributeNoCapture);
- if (I->hasStructRetAttr())
- BA->addAttr(FunctionParameterAttributeSret);
- if (Attrs.hasAttribute(ArgNo + 1, Attribute::ZExt))
- BA->addAttr(FunctionParameterAttributeZext);
- if (Attrs.hasAttribute(ArgNo + 1, Attribute::SExt))
- BA->addAttr(FunctionParameterAttributeSext);
- if (Attrs.hasAttribute(ArgNo + 1, Attribute::Dereferenceable))
- BA->addDecorate(DecorationMaxByteOffset,
- Attrs.getAttribute(ArgNo + 1, Attribute::Dereferenceable)
- .getDereferenceableBytes());
- }
- if (Attrs.hasAttribute(AttributeList::ReturnIndex, Attribute::ZExt))
- BF->addDecorate(DecorationFuncParamAttr, FunctionParameterAttributeZext);
- if (Attrs.hasAttribute(AttributeList::ReturnIndex, Attribute::SExt))
- BF->addDecorate(DecorationFuncParamAttr, FunctionParameterAttributeSext);
- DbgTran.transDbgInfo(F, BF);
- SPIRVDBG(dbgs() << "[transFunction] " << *F << " => ";
- spvdbgs() << *BF << '\n';)
- return BF;
-}
-
-#define _SPIRV_OPL(x) OpLogical##x
-
-#define _SPIRV_OPB(x) OpBitwise##x
-
-SPIRVValue *
-LLVMToSPIRV::transConstant(Value *V) {
- if (auto CPNull = dyn_cast<ConstantPointerNull>(V))
- return BM->addNullConstant(bcast<SPIRVTypePointer>(transType(
- CPNull->getType())));
-
- if (auto CAZero = dyn_cast<ConstantAggregateZero>(V)) {
- Type *AggType = CAZero->getType();
- if (const StructType* ST = dyn_cast<StructType>(AggType))
- if (ST->getName() == getSPIRVTypeName(kSPIRVTypeName::ConstantSampler))
- return BM->addSamplerConstant(transType(AggType), 0,0,0);
-
- return BM->addNullConstant(transType(AggType));
- }
-
- if (auto ConstI = dyn_cast<ConstantInt>(V))
- return BM->addConstant(transType(V->getType()), ConstI->getZExtValue());
-
- if (auto ConstFP = dyn_cast<ConstantFP>(V)) {
- auto BT = static_cast<SPIRVType *>(transType(V->getType()));
- return BM->addConstant(BT,
- ConstFP->getValueAPF().bitcastToAPInt().getZExtValue());
- }
-
- if (auto ConstDA = dyn_cast<ConstantDataArray>(V)) {
- std::vector<SPIRVValue *> BV;
- for (unsigned I = 0, E = ConstDA->getNumElements(); I != E; ++I)
- BV.push_back(transValue(ConstDA->getElementAsConstant(I), nullptr));
- return BM->addCompositeConstant(transType(V->getType()), BV);
- }
-
- if (auto ConstA = dyn_cast<ConstantArray>(V)) {
- std::vector<SPIRVValue *> BV;
- for (auto I = ConstA->op_begin(), E = ConstA->op_end(); I != E; ++I)
- BV.push_back(transValue(*I, nullptr));
- return BM->addCompositeConstant(transType(V->getType()), BV);
- }
-
- if (auto ConstDV = dyn_cast<ConstantDataVector>(V)) {
- std::vector<SPIRVValue *> BV;
- for (unsigned I = 0, E = ConstDV->getNumElements(); I != E; ++I)
- BV.push_back(transValue(ConstDV->getElementAsConstant(I), nullptr));
- return BM->addCompositeConstant(transType(V->getType()), BV);
- }
-
- if (auto ConstV = dyn_cast<ConstantVector>(V)) {
- std::vector<SPIRVValue *> BV;
- for (auto I = ConstV->op_begin(), E = ConstV->op_end(); I != E; ++I)
- BV.push_back(transValue(*I, nullptr));
- return BM->addCompositeConstant(transType(V->getType()), BV);
- }
-
- if (auto ConstV = dyn_cast<ConstantStruct>(V)) {
- if (ConstV->getType()->getName() ==
- getSPIRVTypeName(kSPIRVTypeName::ConstantSampler)) {
- assert(ConstV->getNumOperands() == 3);
- SPIRVWord
- AddrMode = ConstV->getOperand(0)->getUniqueInteger().getZExtValue(),
- Normalized = ConstV->getOperand(1)->getUniqueInteger().getZExtValue(),
- FilterMode = ConstV->getOperand(2)->getUniqueInteger().getZExtValue();
- assert(AddrMode < 5 && "Invalid addressing mode");
- assert(Normalized < 2 && "Invalid value of normalized coords");
- assert(FilterMode < 2 && "Invalid filter mode");
- SPIRVType* SamplerTy = transType(ConstV->getType());
- return BM->addSamplerConstant(SamplerTy,
- AddrMode, Normalized, FilterMode);
- }
- if (ConstV->getType()->getName() ==
- getSPIRVTypeName(kSPIRVTypeName::ConstantPipeStorage)) {
- assert(ConstV->getNumOperands() == 3);
- SPIRVWord
- PacketSize = ConstV->getOperand(0)->getUniqueInteger().getZExtValue(),
- PacketAlign = ConstV->getOperand(1)->getUniqueInteger().getZExtValue(),
- Capacity = ConstV->getOperand(2)->getUniqueInteger().getZExtValue();
- assert(PacketAlign >= 1 && "Invalid packet alignment");
- assert(PacketSize >= PacketAlign && PacketSize % PacketAlign == 0 &&
- "Invalid packet size and/or alignment.");
- SPIRVType* PipeStorageTy = transType(ConstV->getType());
- return BM->addPipeStorageConstant(PipeStorageTy, PacketSize, PacketAlign,
- Capacity);
- }
- std::vector<SPIRVValue *> BV;
- for (auto I = ConstV->op_begin(), E = ConstV->op_end(); I != E; ++I)
- BV.push_back(transValue(*I, nullptr));
- return BM->addCompositeConstant(transType(V->getType()), BV);
- }
-
- if (auto ConstUE = dyn_cast<ConstantExpr>(V)) {
- auto Inst = ConstUE->getAsInstruction();
- SPIRVDBG(dbgs() << "ConstantExpr: " << *ConstUE << '\n';
- dbgs() << "Instruction: " << *Inst << '\n';)
- auto BI = transValue(Inst, nullptr, false);
- Inst->dropAllReferences();
- return BI;
- }
-
- if (isa<UndefValue>(V)) {
- return BM->addUndef(transType(V->getType()));
- }
-
- return nullptr;
-}
-
-SPIRVValue *
-LLVMToSPIRV::transValue(Value *V, SPIRVBasicBlock *BB, bool CreateForward) {
- LLVMToSPIRVValueMap::iterator Loc = ValueMap.find(V);
- if (Loc != ValueMap.end() && (!Loc->second->isForward() || CreateForward))
- return Loc->second;
-
- SPIRVDBG(dbgs() << "[transValue] " << *V << '\n');
- assert ((!isa<Instruction>(V) || isa<GetElementPtrInst>(V) ||
- isa<CastInst>(V) || BB) &&
- "Invalid SPIRV BB");
-
- auto BV = transValueWithoutDecoration(V, BB, CreateForward);
- if (!BV || !transDecoration(V, BV))
- return nullptr;
- std::string name = V->getName();
- if (!name.empty()) // Don't erase the name, which BM might already have
- BM->setName(BV, name);
- return BV;
-}
-
-SPIRVInstruction*
-LLVMToSPIRV::transBinaryInst(BinaryOperator* B, SPIRVBasicBlock* BB) {
- unsigned LLVMOC = B->getOpcode();
- auto Op0 = transValue(B->getOperand(0), BB);
- SPIRVInstruction* BI = BM->addBinaryInst(
- transBoolOpCode(Op0, OpCodeMap::map(LLVMOC)),
- transType(B->getType()), Op0, transValue(B->getOperand(1), BB), BB);
- return BI;
-}
-
-SPIRVInstruction*
-LLVMToSPIRV::transCmpInst(CmpInst* Cmp, SPIRVBasicBlock* BB) {
- auto Op0 = transValue(Cmp->getOperand(0), BB);
- SPIRVInstruction* BI = BM->addCmpInst(
- transBoolOpCode(Op0, CmpMap::map(Cmp->getPredicate())),
- transType(Cmp->getType()), Op0,
- transValue(Cmp->getOperand(1), BB), BB);
- return BI;
-}
-
-SPIRVInstruction *
-LLVMToSPIRV::transLifetimeIntrinsicInst(Op OC, IntrinsicInst *II, SPIRVBasicBlock *BB) {
- int64_t Size = dyn_cast<ConstantInt>(II->getOperand(0))->getSExtValue();
- if (Size == -1)
- Size = 0;
- auto Op1 = II->getOperand(1);
-
- if (auto AI = dyn_cast<AllocaInst>(Op1)) {
- (void)AI;
- assert((!Size ||
- M->getDataLayout().getTypeSizeInBits(AI->getAllocatedType()) ==
- (uint64_t)(Size * 8)) &&
- "Size of the argument should match the allocated memory");
- return BM->addLifetimeInst(OC, transValue(Op1, BB), Size, BB);
- }
- // Bitcast might be inserted during translation of OpLifetimeStart
- assert(isa<BitCastInst>(Op1));
- for (const auto &U : Op1->users()) {
- auto BCU = dyn_cast<IntrinsicInst>(U);
+ assert(!ST->getName().startswith(kSPR2TypeName::Pipe)); + assert(!ST->getName().startswith(kSPR2TypeName::ImagePrefix)); + return mapType(T, BM->addOpaqueType(T->getStructName())); + } + + if (auto ST = dyn_cast<StructType>(T)) { + assert(ST->isSized()); + + std::string Name; + if (ST->hasName()) + Name = ST->getName(); + + if(Name == getSPIRVTypeName(kSPIRVTypeName::ConstantSampler)) + return transType(getSamplerType(M)); + if (Name == getSPIRVTypeName(kSPIRVTypeName::ConstantPipeStorage)) + return transType(getPipeStorageType(M)); + + auto *Struct = BM->openStructType(T->getStructNumElements(), Name); + mapType(T, Struct); + + SmallVector<unsigned, 4> ForwardRefs; + + for (unsigned I = 0, E = T->getStructNumElements(); I != E; ++I) { + auto *ElemTy = ST->getElementType(I); + if ((isa<CompositeType>(ElemTy) || isa<PointerType>(ElemTy)) && recursiveType(ST, ElemTy)) + ForwardRefs.push_back(I); + else + Struct->setMemberType(I, transType(ST->getElementType(I))); + } + + BM->closeStructType(Struct, ST->isPacked()); + + for (auto I : ForwardRefs) + Struct->setMemberType(I, transType(ST->getElementType(I))); + + return Struct; + } + + if (FunctionType *FT = dyn_cast<FunctionType>(T)) { + SPIRVType *RT = transType(FT->getReturnType()); + std::vector<SPIRVType *> PT; + for (FunctionType::param_iterator I = FT->param_begin(), + E = FT->param_end(); + I != E; ++I) + PT.push_back(transType(*I)); + return mapType(T, BM->addFunctionType(RT, PT)); + } + + llvm_unreachable("Not implemented!"); + return 0; +} + +SPIRVType * +LLVMToSPIRV::transSPIRVOpaqueType(Type *T) { + auto ET = T->getPointerElementType(); + auto ST = cast<StructType>(ET); + auto STName = ST->getStructName(); + assert (STName.startswith(kSPIRVTypeName::PrefixAndDelim) && + "Invalid SPIR-V opaque type name"); + SmallVector<std::string, 8> Postfixes; + auto TN = decodeSPIRVTypeName(STName, Postfixes); + if (TN == kSPIRVTypeName::Pipe) { + assert(T->getPointerAddressSpace() == SPIRAS_Global); + assert(Postfixes.size() == 1 && "Invalid pipe type ops"); + auto PipeT = BM->addPipeType(); + PipeT->setPipeAcessQualifier(static_cast<spv::AccessQualifier>( + atoi(Postfixes[0].c_str()))); + return mapType(T, PipeT); + } else if (TN == kSPIRVTypeName::Image) { + assert(T->getPointerAddressSpace() == SPIRAS_Global); + // The sampled type needs to be translated through LLVM type to guarantee + // uniqueness. + auto SampledT = transType(getLLVMTypeForSPIRVImageSampledTypePostfix( + Postfixes[0], *Ctx)); + SmallVector<int, 7> Ops; + for (unsigned I = 1; I < 8; ++I) + Ops.push_back(atoi(Postfixes[I].c_str())); + SPIRVTypeImageDescriptor Desc(static_cast<SPIRVImageDimKind>(Ops[0]), + Ops[1], Ops[2], Ops[3], Ops[4], Ops[5]); + return mapType(T, BM->addImageType(SampledT, Desc, + static_cast<spv::AccessQualifier>(Ops[6]))); + } else if (TN == kSPIRVTypeName::SampledImg) { + return mapType(T, BM->addSampledImageType( + static_cast<SPIRVTypeImage *>( + transType(getSPIRVTypeByChangeBaseTypeName(M, + T, kSPIRVTypeName::SampledImg, + kSPIRVTypeName::Image))))); + } else if(TN == kSPIRVTypeName::Sampler) + return mapType(T, BM->addSamplerType()); + else if (TN == kSPIRVTypeName::DeviceEvent) + return mapType(T, BM->addDeviceEventType()); + else if (TN == kSPIRVTypeName::Queue) + return mapType(T, BM->addQueueType()); + else if (TN == kSPIRVTypeName::PipeStorage) + return mapType(T, BM->addPipeStorageType()); + else + return mapType(T, BM->addOpaqueGenericType( + SPIRVOpaqueTypeOpCodeMap::map(TN))); +} + +SPIRVFunction * +LLVMToSPIRV::transFunctionDecl(Function *F) { + if (auto BF = getTranslatedValue(F)) + return static_cast<SPIRVFunction *>(BF); + + if (F->isIntrinsic()) { + // We should not translate LLVM intrinsics as a function + assert(none_of(F->user_begin(), F->user_end(), + [this](User *U){ return getTranslatedValue(U);}) && + "LLVM intrinsics shouldn't be called in SPIRV"); + return nullptr; + } + + SPIRVTypeFunction *BFT = static_cast<SPIRVTypeFunction *>(transType( + getAnalysis<OCLTypeToSPIRV>().getAdaptedType(F))); + SPIRVFunction *BF = static_cast<SPIRVFunction *>(mapValue(F, + BM->addFunction(BFT))); + BF->setFunctionControlMask(transFunctionControlMask(F)); + if (F->hasName()) + BM->setName(BF, F->getName()); + if (oclIsKernel(F)) + BM->addEntryPoint(ExecutionModelKernel, BF->getId()); + else if (F->getLinkage() != GlobalValue::InternalLinkage) + BF->setLinkageType(transLinkageType(F)); + auto Attrs = F->getAttributes(); + for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; + ++I) { + auto ArgNo = I->getArgNo(); + SPIRVFunctionParameter *BA = BF->getArgument(ArgNo); + if (I->hasName()) + BM->setName(BA, I->getName()); + if (I->hasByValAttr()) + BA->addAttr(FunctionParameterAttributeByVal); + if (I->hasNoAliasAttr()) + BA->addAttr(FunctionParameterAttributeNoAlias); + if (I->hasNoCaptureAttr()) + BA->addAttr(FunctionParameterAttributeNoCapture); + if (I->hasStructRetAttr()) + BA->addAttr(FunctionParameterAttributeSret); + if (Attrs.hasAttribute(ArgNo + 1, Attribute::ZExt)) + BA->addAttr(FunctionParameterAttributeZext); + if (Attrs.hasAttribute(ArgNo + 1, Attribute::SExt)) + BA->addAttr(FunctionParameterAttributeSext); + if (Attrs.hasAttribute(ArgNo + 1, Attribute::Dereferenceable)) + BA->addDecorate(DecorationMaxByteOffset, + Attrs.getAttribute(ArgNo + 1, Attribute::Dereferenceable) + .getDereferenceableBytes()); + } + if (Attrs.hasAttribute(AttributeList::ReturnIndex, Attribute::ZExt)) + BF->addDecorate(DecorationFuncParamAttr, FunctionParameterAttributeZext); + if (Attrs.hasAttribute(AttributeList::ReturnIndex, Attribute::SExt)) + BF->addDecorate(DecorationFuncParamAttr, FunctionParameterAttributeSext); + DbgTran.transDbgInfo(F, BF); + SPIRVDBG(dbgs() << "[transFunction] " << *F << " => "; + spvdbgs() << *BF << '\n';) + return BF; +} + +#define _SPIRV_OPL(x) OpLogical##x + +#define _SPIRV_OPB(x) OpBitwise##x + +SPIRVValue * +LLVMToSPIRV::transConstant(Value *V) { + if (auto CPNull = dyn_cast<ConstantPointerNull>(V)) + return BM->addNullConstant(bcast<SPIRVTypePointer>(transType( + CPNull->getType()))); + + if (auto CAZero = dyn_cast<ConstantAggregateZero>(V)) { + Type *AggType = CAZero->getType(); + if (const StructType* ST = dyn_cast<StructType>(AggType)) + if (ST->getName() == getSPIRVTypeName(kSPIRVTypeName::ConstantSampler)) + return BM->addSamplerConstant(transType(AggType), 0,0,0); + + return BM->addNullConstant(transType(AggType)); + } + + if (auto ConstI = dyn_cast<ConstantInt>(V)) + return BM->addConstant(transType(V->getType()), ConstI->getZExtValue()); + + if (auto ConstFP = dyn_cast<ConstantFP>(V)) { + auto BT = static_cast<SPIRVType *>(transType(V->getType())); + return BM->addConstant(BT, + ConstFP->getValueAPF().bitcastToAPInt().getZExtValue()); + } + + if (auto ConstDA = dyn_cast<ConstantDataArray>(V)) { + std::vector<SPIRVValue *> BV; + for (unsigned I = 0, E = ConstDA->getNumElements(); I != E; ++I) + BV.push_back(transValue(ConstDA->getElementAsConstant(I), nullptr)); + return BM->addCompositeConstant(transType(V->getType()), BV); + } + + if (auto ConstA = dyn_cast<ConstantArray>(V)) { + std::vector<SPIRVValue *> BV; + for (auto I = ConstA->op_begin(), E = ConstA->op_end(); I != E; ++I) + BV.push_back(transValue(*I, nullptr)); + return BM->addCompositeConstant(transType(V->getType()), BV); + } + + if (auto ConstDV = dyn_cast<ConstantDataVector>(V)) { + std::vector<SPIRVValue *> BV; + for (unsigned I = 0, E = ConstDV->getNumElements(); I != E; ++I) + BV.push_back(transValue(ConstDV->getElementAsConstant(I), nullptr)); + return BM->addCompositeConstant(transType(V->getType()), BV); + } + + if (auto ConstV = dyn_cast<ConstantVector>(V)) { + std::vector<SPIRVValue *> BV; + for (auto I = ConstV->op_begin(), E = ConstV->op_end(); I != E; ++I) + BV.push_back(transValue(*I, nullptr)); + return BM->addCompositeConstant(transType(V->getType()), BV); + } + + if (auto ConstV = dyn_cast<ConstantStruct>(V)) { + if (ConstV->getType()->getName() == + getSPIRVTypeName(kSPIRVTypeName::ConstantSampler)) { + assert(ConstV->getNumOperands() == 3); + SPIRVWord + AddrMode = ConstV->getOperand(0)->getUniqueInteger().getZExtValue(), + Normalized = ConstV->getOperand(1)->getUniqueInteger().getZExtValue(), + FilterMode = ConstV->getOperand(2)->getUniqueInteger().getZExtValue(); + assert(AddrMode < 5 && "Invalid addressing mode"); + assert(Normalized < 2 && "Invalid value of normalized coords"); + assert(FilterMode < 2 && "Invalid filter mode"); + SPIRVType* SamplerTy = transType(ConstV->getType()); + return BM->addSamplerConstant(SamplerTy, + AddrMode, Normalized, FilterMode); + } + if (ConstV->getType()->getName() == + getSPIRVTypeName(kSPIRVTypeName::ConstantPipeStorage)) { + assert(ConstV->getNumOperands() == 3); + SPIRVWord + PacketSize = ConstV->getOperand(0)->getUniqueInteger().getZExtValue(), + PacketAlign = ConstV->getOperand(1)->getUniqueInteger().getZExtValue(), + Capacity = ConstV->getOperand(2)->getUniqueInteger().getZExtValue(); + assert(PacketAlign >= 1 && "Invalid packet alignment"); + assert(PacketSize >= PacketAlign && PacketSize % PacketAlign == 0 && + "Invalid packet size and/or alignment."); + SPIRVType* PipeStorageTy = transType(ConstV->getType()); + return BM->addPipeStorageConstant(PipeStorageTy, PacketSize, PacketAlign, + Capacity); + } + std::vector<SPIRVValue *> BV; + for (auto I = ConstV->op_begin(), E = ConstV->op_end(); I != E; ++I) + BV.push_back(transValue(*I, nullptr)); + return BM->addCompositeConstant(transType(V->getType()), BV); + } + + if (auto ConstUE = dyn_cast<ConstantExpr>(V)) { + auto Inst = ConstUE->getAsInstruction(); + SPIRVDBG(dbgs() << "ConstantExpr: " << *ConstUE << '\n'; + dbgs() << "Instruction: " << *Inst << '\n';) + auto BI = transValue(Inst, nullptr, false); + Inst->dropAllReferences(); + return BI; + } + + if (isa<UndefValue>(V)) { + return BM->addUndef(transType(V->getType())); + } + + return nullptr; +} + +SPIRVValue * +LLVMToSPIRV::transValue(Value *V, SPIRVBasicBlock *BB, bool CreateForward) { + LLVMToSPIRVValueMap::iterator Loc = ValueMap.find(V); + if (Loc != ValueMap.end() && (!Loc->second->isForward() || CreateForward)) + return Loc->second; + + SPIRVDBG(dbgs() << "[transValue] " << *V << '\n'); + assert ((!isa<Instruction>(V) || isa<GetElementPtrInst>(V) || + isa<CastInst>(V) || BB) && + "Invalid SPIRV BB"); + + auto BV = transValueWithoutDecoration(V, BB, CreateForward); + if (!BV || !transDecoration(V, BV)) + return nullptr; + std::string name = V->getName(); + if (!name.empty()) // Don't erase the name, which BM might already have + BM->setName(BV, name); + return BV; +} + +SPIRVInstruction* +LLVMToSPIRV::transBinaryInst(BinaryOperator* B, SPIRVBasicBlock* BB) { + unsigned LLVMOC = B->getOpcode(); + auto Op0 = transValue(B->getOperand(0), BB); + SPIRVInstruction* BI = BM->addBinaryInst( + transBoolOpCode(Op0, OpCodeMap::map(LLVMOC)), + transType(B->getType()), Op0, transValue(B->getOperand(1), BB), BB); + return BI; +} + +SPIRVInstruction* +LLVMToSPIRV::transCmpInst(CmpInst* Cmp, SPIRVBasicBlock* BB) { + auto Op0 = transValue(Cmp->getOperand(0), BB); + SPIRVInstruction* BI = BM->addCmpInst( + transBoolOpCode(Op0, CmpMap::map(Cmp->getPredicate())), + transType(Cmp->getType()), Op0, + transValue(Cmp->getOperand(1), BB), BB); + return BI; +} + +SPIRVInstruction * +LLVMToSPIRV::transLifetimeIntrinsicInst(Op OC, IntrinsicInst *II, SPIRVBasicBlock *BB) { + int64_t Size = dyn_cast<ConstantInt>(II->getOperand(0))->getSExtValue(); + if (Size == -1) + Size = 0; + auto Op1 = II->getOperand(1); + + if (auto AI = dyn_cast<AllocaInst>(Op1)) { + (void)AI; + assert((!Size || + M->getDataLayout().getTypeSizeInBits(AI->getAllocatedType()) == + (uint64_t)(Size * 8)) && + "Size of the argument should match the allocated memory"); + return BM->addLifetimeInst(OC, transValue(Op1, BB), Size, BB); + } + // Bitcast might be inserted during translation of OpLifetimeStart + assert(isa<BitCastInst>(Op1)); + for (const auto &U : Op1->users()) { + auto BCU = dyn_cast<IntrinsicInst>(U); (void)BCU; - assert(BCU && (BCU->getIntrinsicID() == Intrinsic::lifetime_start ||
- BCU->getIntrinsicID() == Intrinsic::lifetime_end) &&
- "The only users of this bitcast instruction are lifetime intrinsics");
- }
- auto AI = dyn_cast<AllocaInst>(dyn_cast<BitCastInst>(Op1)->getOperand(0));
- assert(AI && (!Size ||
- M->getDataLayout().getTypeSizeInBits(AI->getAllocatedType()) ==
- (uint64_t)(Size * 8)) &&
- "Size of the argument should match the allocated memory");
- auto LT = BM->addLifetimeInst(OC, transValue(AI, BB), Size, BB);
- auto BC = LT->getPrevious();
- if (BC && BC->getOpCode() == OpBitcast)
- BM->eraseInstruction(BC, BB);
- return LT;
-}
-
-SPIRV::SPIRVInstruction *LLVMToSPIRV::transUnaryInst(UnaryInstruction *U,
- SPIRVBasicBlock *BB) {
- Op BOC = OpNop;
- if (auto Cast = dyn_cast<AddrSpaceCastInst>(U)) {
- if (Cast->getDestTy()->getPointerAddressSpace() == SPIRAS_Generic) {
- assert(Cast->getSrcTy()->getPointerAddressSpace() != SPIRAS_Constant &&
- "Casts from constant address space to generic are illegal");
- BOC = OpPtrCastToGeneric;
- } else {
- assert(Cast->getDestTy()->getPointerAddressSpace() != SPIRAS_Constant &&
- "Casts from generic address space to constant are illegal");
- assert(Cast->getSrcTy()->getPointerAddressSpace() == SPIRAS_Generic);
- BOC = OpGenericCastToPtr;
- }
- } else {
- auto OpCode = U->getOpcode();
- BOC = OpCodeMap::map(OpCode);
- }
-
- auto Op = transValue(U->getOperand(0), BB);
- return BM->addUnaryInst(transBoolOpCode(Op, BOC),
- transType(U->getType()), Op, BB);
-}
-
-/// An instruction may use an instruction from another BB which has not been
-/// translated. SPIRVForward should be created as place holder for these
-/// instructions and replaced later by the real instructions.
-/// Use CreateForward = true to indicate such situation.
-SPIRVValue *
-LLVMToSPIRV::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB,
- bool CreateForward) {
- if (auto LBB = dyn_cast<BasicBlock>(V)) {
- auto BF = static_cast<SPIRVFunction *>(getTranslatedValue(LBB->getParent()));
- assert (BF && "Function not translated");
- BB = static_cast<SPIRVBasicBlock *>(mapValue(V, BM->addBasicBlock(BF)));
- BM->setName(BB, LBB->getName());
- return BB;
- }
-
- if (auto F = dyn_cast<Function>(V))
- return transFunctionDecl(F);
-
- if (auto GV = dyn_cast<GlobalVariable>(V)) {
- llvm::PointerType * Ty = GV->getType();
- // Though variables with common linkage type are initialized by 0,
- // they can be represented in SPIR-V as uninitialized variables with
- // 'Export' linkage type, just as tentative definitions look in C
- llvm::Value *Init = GV->hasInitializer() && !GV->hasCommonLinkage() ?
- GV->getInitializer() : nullptr;
- StructType *ST = Init ? dyn_cast<StructType>(Init->getType()) : nullptr;
- if (ST && ST->hasName() && isSPIRVConstantName(ST->getName())) {
- auto BV = transConstant(Init);
- assert(BV);
- return mapValue(V, BV);
- } else if (ConstantExpr *ConstUE = dyn_cast_or_null<ConstantExpr>(Init)) {
- Instruction * Inst = ConstUE->getAsInstruction();
- if (isSpecialTypeInitializer(Inst)) {
- Init = Inst->getOperand(0);
- Ty = static_cast<PointerType*>(Init->getType());
- }
- Inst->dropAllReferences();
- }
- auto BVar = static_cast<SPIRVVariable *>(BM->addVariable(
- transType(Ty), GV->isConstant(),
- transLinkageType(GV),
- (Init && !isa<UndefValue>(Init)) ? transValue(Init, nullptr) : nullptr,
- GV->getName(),
- SPIRSPIRVAddrSpaceMap::map(
- static_cast<SPIRAddressSpace>(Ty->getAddressSpace())),
- nullptr
- ));
- mapValue(V, BVar);
- spv::BuiltIn Builtin = spv::BuiltInPosition;
- if (!GV->hasName() || !getSPIRVBuiltin(GV->getName().str(), Builtin))
- return BVar;
- BVar->setBuiltin(Builtin);
- return BVar;
- }
-
- if (isa<Constant>(V)) {
- auto BV = transConstant(V);
- assert(BV);
- return mapValue(V, BV);
- }
-
- if (auto Arg = dyn_cast<Argument>(V)) {
- unsigned ArgNo = Arg->getArgNo();
- SPIRVFunction *BF = BB->getParent();
- //assert(BF->existArgument(ArgNo));
- return mapValue(V, BF->getArgument(ArgNo));
- }
-
- if (CreateForward)
- return mapValue(V, BM->addForward(transType(V->getType())));
-
- if (StoreInst *ST = dyn_cast<StoreInst>(V)) {
- std::vector<SPIRVWord> MemoryAccess(1,0);
- if (ST->isVolatile())
- MemoryAccess[0] |= MemoryAccessVolatileMask;
- if (ST->getAlignment()) {
- MemoryAccess[0] |= MemoryAccessAlignedMask;
- MemoryAccess.push_back(ST->getAlignment());
- }
- if (ST->getMetadata(LLVMContext::MD_nontemporal))
- MemoryAccess[0] |= MemoryAccessNontemporalMask;
- if (MemoryAccess.front() == 0)
- MemoryAccess.clear();
- return mapValue(V, BM->addStoreInst(
- transValue(ST->getPointerOperand(), BB),
- transValue(ST->getValueOperand(), BB),
- MemoryAccess, BB));
- }
-
- if (LoadInst *LD = dyn_cast<LoadInst>(V)) {
- std::vector<SPIRVWord> MemoryAccess(1,0);
- if (LD->isVolatile())
- MemoryAccess[0] |= MemoryAccessVolatileMask;
- if (LD->getAlignment()) {
- MemoryAccess[0] |= MemoryAccessAlignedMask;
- MemoryAccess.push_back(LD->getAlignment());
- }
- if (LD->getMetadata(LLVMContext::MD_nontemporal))
- MemoryAccess[0] |= MemoryAccessNontemporalMask;
- if (MemoryAccess.front() == 0)
- MemoryAccess.clear();
- return mapValue(V, BM->addLoadInst(
- transValue(LD->getPointerOperand(), BB),
- MemoryAccess, BB));
- }
-
- if (BinaryOperator *B = dyn_cast<BinaryOperator>(V)) {
- SPIRVInstruction* BI = transBinaryInst(B, BB);
- return mapValue(V, BI);
- }
-
- if (dyn_cast<UnreachableInst>(V))
- return mapValue(V, BM->addUnreachableInst(BB));
-
- if (auto RI = dyn_cast<ReturnInst>(V)) {
- if (auto RV = RI->getReturnValue())
- return mapValue(V, BM->addReturnValueInst(
- transValue(RV, BB), BB));
- return mapValue(V, BM->addReturnInst(BB));
- }
-
- if (CmpInst *Cmp = dyn_cast<CmpInst>(V)) {
- SPIRVInstruction* BI = transCmpInst(Cmp, BB);
- return mapValue(V, BI);
- }
-
- if (SelectInst *Sel = dyn_cast<SelectInst>(V))
- return mapValue(V, BM->addSelectInst(
- transValue(Sel->getCondition(), BB),
- transValue(Sel->getTrueValue(), BB),
- transValue(Sel->getFalseValue(), BB),BB));
-
- if (AllocaInst *Alc = dyn_cast<AllocaInst>(V))
- return mapValue(V, BM->addVariable(
- transType(Alc->getType()), false,
- SPIRVLinkageTypeKind::LinkageTypeInternal,
- nullptr, Alc->getName(),
- StorageClassFunction, BB));
-
- if (auto *Switch = dyn_cast<SwitchInst>(V)) {
- std::vector<SPIRVSwitch::PairTy> Pairs;
- auto Select = transValue(Switch->getCondition(), BB);
-
- for (auto I = Switch->case_begin(), E = Switch->case_end(); I != E; ++I) {
- SPIRVSwitch::LiteralTy Lit;
- uint64_t CaseValue = I->getCaseValue()->getZExtValue();
-
- Lit.push_back(CaseValue);
- assert(Select->getType()->getBitWidth() <= 64 && "unexpected selector bitwidth");
- if(Select->getType()->getBitWidth() == 64)
- Lit.push_back(CaseValue >> 32);
-
- Pairs.push_back(std::make_pair(Lit,
- static_cast<SPIRVBasicBlock*>(transValue(I->getCaseSuccessor(),
- nullptr))));
- }
-
- return mapValue(V, BM->addSwitchInst(Select,
- static_cast<SPIRVBasicBlock*>(transValue(Switch->getDefaultDest(),
- nullptr)), Pairs, BB));
- }
-
- if (auto Branch = dyn_cast<BranchInst>(V)) {
- if (Branch->isUnconditional())
- return mapValue(V, BM->addBranchInst(
- static_cast<SPIRVLabel*>(transValue(Branch->getSuccessor(0), BB)),
- BB));
- return mapValue(V, BM->addBranchConditionalInst(
- transValue(Branch->getCondition(), BB),
- static_cast<SPIRVLabel*>(transValue(Branch->getSuccessor(0), BB)),
- static_cast<SPIRVLabel*>(transValue(Branch->getSuccessor(1), BB)),
- BB));
- }
-
- if (auto Phi = dyn_cast<PHINode>(V)) {
- std::vector<SPIRVValue *> IncomingPairs;
- for (size_t I = 0, E = Phi->getNumIncomingValues(); I != E; ++I) {
- IncomingPairs.push_back(transValue(Phi->getIncomingValue(I), BB));
- IncomingPairs.push_back(transValue(Phi->getIncomingBlock(I), nullptr));
- }
- return mapValue(V, BM->addPhiInst(transType(Phi->getType()), IncomingPairs,
- BB));
- }
-
- if (auto Ext = dyn_cast<ExtractValueInst>(V)) {
- return mapValue(V, BM->addCompositeExtractInst(
- transType(Ext->getType()),
- transValue(Ext->getAggregateOperand(), BB),
- Ext->getIndices(), BB));
- }
-
- if (auto Ins = dyn_cast<InsertValueInst>(V)) {
- return mapValue(V, BM->addCompositeInsertInst(
- transValue(Ins->getInsertedValueOperand(), BB),
- transValue(Ins->getAggregateOperand(), BB),
- Ins->getIndices(), BB));
- }
-
- if (UnaryInstruction *U = dyn_cast<UnaryInstruction>(V)) {
- if (isSpecialTypeInitializer(U))
- return mapValue(V, transValue(U->getOperand(0), BB));
- return mapValue(V, transUnaryInst(U, BB));
- }
-
- if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V)) {
- std::vector<SPIRVValue *> Indices;
- for (unsigned i = 0, e = GEP->getNumIndices(); i != e; ++i)
- Indices.push_back(transValue(GEP->getOperand(i+1), BB));
- return mapValue(V, BM->addPtrAccessChainInst(
- transType(GEP->getType()),
- transValue(GEP->getPointerOperand(), BB),
- Indices, BB, GEP->isInBounds()));
- }
-
- if (auto Ext = dyn_cast<ExtractElementInst>(V)) {
- auto Index = Ext->getIndexOperand();
- if (auto Const = dyn_cast<ConstantInt>(Index))
- return mapValue(V, BM->addCompositeExtractInst(
- transType(Ext->getType()),
- transValue(Ext->getVectorOperand(), BB),
- std::vector<SPIRVWord>(1, Const->getZExtValue()),
- BB));
- else
- return mapValue(V, BM->addVectorExtractDynamicInst(
- transValue(Ext->getVectorOperand(), BB),
- transValue(Index, BB),
- BB));
- }
-
- if (auto Ins = dyn_cast<InsertElementInst>(V)) {
- auto Index = Ins->getOperand(2);
- if (auto Const = dyn_cast<ConstantInt>(Index))
- return mapValue(V, BM->addCompositeInsertInst(
- transValue(Ins->getOperand(1), BB),
- transValue(Ins->getOperand(0), BB),
- std::vector<SPIRVWord>(1, Const->getZExtValue()),
- BB));
- else
- return mapValue(V, BM->addVectorInsertDynamicInst(
- transValue(Ins->getOperand(0), BB),
- transValue(Ins->getOperand(1), BB),
- transValue(Index, BB),
- BB));
- }
-
- if (auto SF = dyn_cast<ShuffleVectorInst>(V)) {
- std::vector<SPIRVWord> Comp;
- for (auto &I:SF->getShuffleMask())
- Comp.push_back(I);
- return mapValue(V, BM->addVectorShuffleInst(
- transType(SF->getType()),
- transValue(SF->getOperand(0), BB),
- transValue(SF->getOperand(1), BB),
- Comp,
- BB));
- }
-
- if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(V)) {
- SPIRVValue *BV = transIntrinsicInst(II, BB);
- return BV ? mapValue(V, BV) : nullptr;
- }
-
- if (CallInst *CI = dyn_cast<CallInst>(V))
- return mapValue(V, transCallInst(CI, BB));
-
- llvm_unreachable("Not implemented");
- return nullptr;
-}
-
-bool
-LLVMToSPIRV::transDecoration(Value *V, SPIRVValue *BV) {
- if (!transAlign(V, BV))
- return false;
- if ((isa<AtomicCmpXchgInst>(V) &&
- cast<AtomicCmpXchgInst>(V)->isVolatile()) ||
- (isa<AtomicRMWInst>(V) && cast<AtomicRMWInst>(V)->isVolatile()))
- BV->setVolatile(true);
- DbgTran.transDbgInfo(V, BV);
- return true;
-}
-
-bool
-LLVMToSPIRV::transAlign(Value *V, SPIRVValue *BV) {
- if (auto AL = dyn_cast<AllocaInst>(V)) {
- BM->setAlignment(BV, AL->getAlignment());
- return true;
- }
- if (auto GV = dyn_cast<GlobalVariable>(V)) {
- BM->setAlignment(BV, GV->getAlignment());
- return true;
- }
- return true;
-}
-
-/// Do this after source language is set.
-bool
-LLVMToSPIRV::transBuiltinSet() {
- SPIRVWord Ver = 0;
+ assert(BCU && (BCU->getIntrinsicID() == Intrinsic::lifetime_start || + BCU->getIntrinsicID() == Intrinsic::lifetime_end) && + "The only users of this bitcast instruction are lifetime intrinsics"); + } + auto AI = dyn_cast<AllocaInst>(dyn_cast<BitCastInst>(Op1)->getOperand(0)); + assert(AI && (!Size || + M->getDataLayout().getTypeSizeInBits(AI->getAllocatedType()) == + (uint64_t)(Size * 8)) && + "Size of the argument should match the allocated memory"); + auto LT = BM->addLifetimeInst(OC, transValue(AI, BB), Size, BB); + auto BC = LT->getPrevious(); + if (BC && BC->getOpCode() == OpBitcast) + BM->eraseInstruction(BC, BB); + return LT; +} + +SPIRV::SPIRVInstruction *LLVMToSPIRV::transUnaryInst(UnaryInstruction *U, + SPIRVBasicBlock *BB) { + Op BOC = OpNop; + if (auto Cast = dyn_cast<AddrSpaceCastInst>(U)) { + if (Cast->getDestTy()->getPointerAddressSpace() == SPIRAS_Generic) { + assert(Cast->getSrcTy()->getPointerAddressSpace() != SPIRAS_Constant && + "Casts from constant address space to generic are illegal"); + BOC = OpPtrCastToGeneric; + } else { + assert(Cast->getDestTy()->getPointerAddressSpace() != SPIRAS_Constant && + "Casts from generic address space to constant are illegal"); + assert(Cast->getSrcTy()->getPointerAddressSpace() == SPIRAS_Generic); + BOC = OpGenericCastToPtr; + } + } else { + auto OpCode = U->getOpcode(); + BOC = OpCodeMap::map(OpCode); + } + + auto Op = transValue(U->getOperand(0), BB); + return BM->addUnaryInst(transBoolOpCode(Op, BOC), + transType(U->getType()), Op, BB); +} + +/// An instruction may use an instruction from another BB which has not been +/// translated. SPIRVForward should be created as place holder for these +/// instructions and replaced later by the real instructions. +/// Use CreateForward = true to indicate such situation. +SPIRVValue * +LLVMToSPIRV::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB, + bool CreateForward) { + if (auto LBB = dyn_cast<BasicBlock>(V)) { + auto BF = static_cast<SPIRVFunction *>(getTranslatedValue(LBB->getParent())); + assert (BF && "Function not translated"); + BB = static_cast<SPIRVBasicBlock *>(mapValue(V, BM->addBasicBlock(BF))); + BM->setName(BB, LBB->getName()); + return BB; + } + + if (auto F = dyn_cast<Function>(V)) + return transFunctionDecl(F); + + if (auto GV = dyn_cast<GlobalVariable>(V)) { + llvm::PointerType * Ty = GV->getType(); + // Though variables with common linkage type are initialized by 0, + // they can be represented in SPIR-V as uninitialized variables with + // 'Export' linkage type, just as tentative definitions look in C + llvm::Value *Init = GV->hasInitializer() && !GV->hasCommonLinkage() ? + GV->getInitializer() : nullptr; + StructType *ST = Init ? dyn_cast<StructType>(Init->getType()) : nullptr; + if (ST && ST->hasName() && isSPIRVConstantName(ST->getName())) { + auto BV = transConstant(Init); + assert(BV); + return mapValue(V, BV); + } else if (ConstantExpr *ConstUE = dyn_cast_or_null<ConstantExpr>(Init)) { + Instruction * Inst = ConstUE->getAsInstruction(); + if (isSpecialTypeInitializer(Inst)) { + Init = Inst->getOperand(0); + Ty = static_cast<PointerType*>(Init->getType()); + } + Inst->dropAllReferences(); + } + auto BVar = static_cast<SPIRVVariable *>(BM->addVariable( + transType(Ty), GV->isConstant(), + transLinkageType(GV), + (Init && !isa<UndefValue>(Init)) ? transValue(Init, nullptr) : nullptr, + GV->getName(), + SPIRSPIRVAddrSpaceMap::map( + static_cast<SPIRAddressSpace>(Ty->getAddressSpace())), + nullptr + )); + mapValue(V, BVar); + spv::BuiltIn Builtin = spv::BuiltInPosition; + if (!GV->hasName() || !getSPIRVBuiltin(GV->getName().str(), Builtin)) + return BVar; + BVar->setBuiltin(Builtin); + return BVar; + } + + if (isa<Constant>(V)) { + auto BV = transConstant(V); + assert(BV); + return mapValue(V, BV); + } + + if (auto Arg = dyn_cast<Argument>(V)) { + unsigned ArgNo = Arg->getArgNo(); + SPIRVFunction *BF = BB->getParent(); + //assert(BF->existArgument(ArgNo)); + return mapValue(V, BF->getArgument(ArgNo)); + } + + if (CreateForward) + return mapValue(V, BM->addForward(transType(V->getType()))); + + if (StoreInst *ST = dyn_cast<StoreInst>(V)) { + std::vector<SPIRVWord> MemoryAccess(1,0); + if (ST->isVolatile()) + MemoryAccess[0] |= MemoryAccessVolatileMask; + if (ST->getAlignment()) { + MemoryAccess[0] |= MemoryAccessAlignedMask; + MemoryAccess.push_back(ST->getAlignment()); + } + if (ST->getMetadata(LLVMContext::MD_nontemporal)) + MemoryAccess[0] |= MemoryAccessNontemporalMask; + if (MemoryAccess.front() == 0) + MemoryAccess.clear(); + return mapValue(V, BM->addStoreInst( + transValue(ST->getPointerOperand(), BB), + transValue(ST->getValueOperand(), BB), + MemoryAccess, BB)); + } + + if (LoadInst *LD = dyn_cast<LoadInst>(V)) { + std::vector<SPIRVWord> MemoryAccess(1,0); + if (LD->isVolatile()) + MemoryAccess[0] |= MemoryAccessVolatileMask; + if (LD->getAlignment()) { + MemoryAccess[0] |= MemoryAccessAlignedMask; + MemoryAccess.push_back(LD->getAlignment()); + } + if (LD->getMetadata(LLVMContext::MD_nontemporal)) + MemoryAccess[0] |= MemoryAccessNontemporalMask; + if (MemoryAccess.front() == 0) + MemoryAccess.clear(); + return mapValue(V, BM->addLoadInst( + transValue(LD->getPointerOperand(), BB), + MemoryAccess, BB)); + } + + if (BinaryOperator *B = dyn_cast<BinaryOperator>(V)) { + SPIRVInstruction* BI = transBinaryInst(B, BB); + return mapValue(V, BI); + } + + if (dyn_cast<UnreachableInst>(V)) + return mapValue(V, BM->addUnreachableInst(BB)); + + if (auto RI = dyn_cast<ReturnInst>(V)) { + if (auto RV = RI->getReturnValue()) + return mapValue(V, BM->addReturnValueInst( + transValue(RV, BB), BB)); + return mapValue(V, BM->addReturnInst(BB)); + } + + if (CmpInst *Cmp = dyn_cast<CmpInst>(V)) { + SPIRVInstruction* BI = transCmpInst(Cmp, BB); + return mapValue(V, BI); + } + + if (SelectInst *Sel = dyn_cast<SelectInst>(V)) + return mapValue(V, BM->addSelectInst( + transValue(Sel->getCondition(), BB), + transValue(Sel->getTrueValue(), BB), + transValue(Sel->getFalseValue(), BB),BB)); + + if (AllocaInst *Alc = dyn_cast<AllocaInst>(V)) + return mapValue(V, BM->addVariable( + transType(Alc->getType()), false, + SPIRVLinkageTypeKind::LinkageTypeInternal, + nullptr, Alc->getName(), + StorageClassFunction, BB)); + + if (auto *Switch = dyn_cast<SwitchInst>(V)) { + std::vector<SPIRVSwitch::PairTy> Pairs; + auto Select = transValue(Switch->getCondition(), BB); + + for (auto I = Switch->case_begin(), E = Switch->case_end(); I != E; ++I) { + SPIRVSwitch::LiteralTy Lit; + uint64_t CaseValue = I->getCaseValue()->getZExtValue(); + + Lit.push_back(CaseValue); + assert(Select->getType()->getBitWidth() <= 64 && "unexpected selector bitwidth"); + if(Select->getType()->getBitWidth() == 64) + Lit.push_back(CaseValue >> 32); + + Pairs.push_back(std::make_pair(Lit, + static_cast<SPIRVBasicBlock*>(transValue(I->getCaseSuccessor(), + nullptr)))); + } + + return mapValue(V, BM->addSwitchInst(Select, + static_cast<SPIRVBasicBlock*>(transValue(Switch->getDefaultDest(), + nullptr)), Pairs, BB)); + } + + if (auto Branch = dyn_cast<BranchInst>(V)) { + if (Branch->isUnconditional()) + return mapValue(V, BM->addBranchInst( + static_cast<SPIRVLabel*>(transValue(Branch->getSuccessor(0), BB)), + BB)); + return mapValue(V, BM->addBranchConditionalInst( + transValue(Branch->getCondition(), BB), + static_cast<SPIRVLabel*>(transValue(Branch->getSuccessor(0), BB)), + static_cast<SPIRVLabel*>(transValue(Branch->getSuccessor(1), BB)), + BB)); + } + + if (auto Phi = dyn_cast<PHINode>(V)) { + std::vector<SPIRVValue *> IncomingPairs; + for (size_t I = 0, E = Phi->getNumIncomingValues(); I != E; ++I) { + IncomingPairs.push_back(transValue(Phi->getIncomingValue(I), BB)); + IncomingPairs.push_back(transValue(Phi->getIncomingBlock(I), nullptr)); + } + return mapValue(V, BM->addPhiInst(transType(Phi->getType()), IncomingPairs, + BB)); + } + + if (auto Ext = dyn_cast<ExtractValueInst>(V)) { + return mapValue(V, BM->addCompositeExtractInst( + transType(Ext->getType()), + transValue(Ext->getAggregateOperand(), BB), + Ext->getIndices(), BB)); + } + + if (auto Ins = dyn_cast<InsertValueInst>(V)) { + return mapValue(V, BM->addCompositeInsertInst( + transValue(Ins->getInsertedValueOperand(), BB), + transValue(Ins->getAggregateOperand(), BB), + Ins->getIndices(), BB)); + } + + if (UnaryInstruction *U = dyn_cast<UnaryInstruction>(V)) { + if (isSpecialTypeInitializer(U)) + return mapValue(V, transValue(U->getOperand(0), BB)); + return mapValue(V, transUnaryInst(U, BB)); + } + + if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V)) { + std::vector<SPIRVValue *> Indices; + for (unsigned i = 0, e = GEP->getNumIndices(); i != e; ++i) + Indices.push_back(transValue(GEP->getOperand(i+1), BB)); + return mapValue(V, BM->addPtrAccessChainInst( + transType(GEP->getType()), + transValue(GEP->getPointerOperand(), BB), + Indices, BB, GEP->isInBounds())); + } + + if (auto Ext = dyn_cast<ExtractElementInst>(V)) { + auto Index = Ext->getIndexOperand(); + if (auto Const = dyn_cast<ConstantInt>(Index)) + return mapValue(V, BM->addCompositeExtractInst( + transType(Ext->getType()), + transValue(Ext->getVectorOperand(), BB), + std::vector<SPIRVWord>(1, Const->getZExtValue()), + BB)); + else + return mapValue(V, BM->addVectorExtractDynamicInst( + transValue(Ext->getVectorOperand(), BB), + transValue(Index, BB), + BB)); + } + + if (auto Ins = dyn_cast<InsertElementInst>(V)) { + auto Index = Ins->getOperand(2); + if (auto Const = dyn_cast<ConstantInt>(Index)) + return mapValue(V, BM->addCompositeInsertInst( + transValue(Ins->getOperand(1), BB), + transValue(Ins->getOperand(0), BB), + std::vector<SPIRVWord>(1, Const->getZExtValue()), + BB)); + else + return mapValue(V, BM->addVectorInsertDynamicInst( + transValue(Ins->getOperand(0), BB), + transValue(Ins->getOperand(1), BB), + transValue(Index, BB), + BB)); + } + + if (auto SF = dyn_cast<ShuffleVectorInst>(V)) { + std::vector<SPIRVWord> Comp; + for (auto &I:SF->getShuffleMask()) + Comp.push_back(I); + return mapValue(V, BM->addVectorShuffleInst( + transType(SF->getType()), + transValue(SF->getOperand(0), BB), + transValue(SF->getOperand(1), BB), + Comp, + BB)); + } + + if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(V)) { + SPIRVValue *BV = transIntrinsicInst(II, BB); + return BV ? mapValue(V, BV) : nullptr; + } + + if (CallInst *CI = dyn_cast<CallInst>(V)) + return mapValue(V, transCallInst(CI, BB)); + + llvm_unreachable("Not implemented"); + return nullptr; +} + +bool +LLVMToSPIRV::transDecoration(Value *V, SPIRVValue *BV) { + if (!transAlign(V, BV)) + return false; + if ((isa<AtomicCmpXchgInst>(V) && + cast<AtomicCmpXchgInst>(V)->isVolatile()) || + (isa<AtomicRMWInst>(V) && cast<AtomicRMWInst>(V)->isVolatile())) + BV->setVolatile(true); + DbgTran.transDbgInfo(V, BV); + return true; +} + +bool +LLVMToSPIRV::transAlign(Value *V, SPIRVValue *BV) { + if (auto AL = dyn_cast<AllocaInst>(V)) { + BM->setAlignment(BV, AL->getAlignment()); + return true; + } + if (auto GV = dyn_cast<GlobalVariable>(V)) { + BM->setAlignment(BV, GV->getAlignment()); + return true; + } + return true; +} + +/// Do this after source language is set. +bool +LLVMToSPIRV::transBuiltinSet() { + SPIRVWord Ver = 0; (void)Ver; - assert((BM->getSourceLanguage(&Ver) == SourceLanguageOpenCL_C ||
- BM->getSourceLanguage(&Ver) == SourceLanguageOpenCL_CPP) &&
- "not supported");
- std::stringstream SS;
- SS << "OpenCL.std";
- return BM->importBuiltinSet(SS.str(), &ExtSetId);
-}
-
-/// Transform sampler* spcv.cast(i32 arg)
-/// Only two cases are possible:
-/// arg = ConstantInt x -> SPIRVConstantSampler
-/// arg = i32 argument -> transValue(arg)
-/// arg = load from sampler -> look through load
-SPIRVValue *
-LLVMToSPIRV::oclTransSpvcCastSampler(CallInst* CI, SPIRVBasicBlock *BB) {
- llvm::Function* F = CI->getCalledFunction();
- auto FT = F->getFunctionType();
- auto RT = FT->getReturnType();
- assert(FT->getNumParams() == 1);
- assert(isSPIRVType(RT, kSPIRVTypeName::Sampler) &&
- FT->getParamType(0)->isIntegerTy() && "Invalid sampler type");
- auto Arg = CI->getArgOperand(0);
-
- auto GetSamplerConstant = [&](uint64_t SamplerValue) {
- auto AddrMode = (SamplerValue & 0xE) >> 1;
- auto Param = SamplerValue & 0x1;
- auto Filter = ((SamplerValue & 0x30) >> 4) - 1;
- auto BV = BM->addSamplerConstant(transType(RT), AddrMode, Param, Filter);
- return BV;
- };
-
- if (auto Const = dyn_cast<ConstantInt>(Arg)) {
- // Sampler is declared as a kernel scope constant
- return GetSamplerConstant(Const->getZExtValue());
- } else if (auto Load = dyn_cast<LoadInst>(Arg)) {
- // If value of the sampler is loaded from a global constant, use its
- // initializer for initialization of the sampler.
- auto Op = Load->getPointerOperand();
- assert(isa<GlobalVariable>(Op) && "Unknown sampler pattern!");
- auto GV = cast<GlobalVariable>(Op);
- assert(GV->isConstant() ||
- GV->getType()->getPointerAddressSpace() == SPIRAS_Constant);
- auto Initializer = GV->getInitializer();
- assert(isa<ConstantInt>(Initializer) && "sampler not constant int?");
- return GetSamplerConstant(cast<ConstantInt>(Initializer)->getZExtValue());
- }
- // Sampler is a function argument
- auto BV = transValue(Arg, BB);
- assert(BV && BV->getType() == transType(RT));
- return BV;
-}
-
-SPIRVValue *
-LLVMToSPIRV::transSpcvCast(CallInst* CI, SPIRVBasicBlock *BB) {
- return oclTransSpvcCastSampler(CI, BB);
-}
-
-SPIRVValue *
-LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, SPIRVBasicBlock *BB) {
- auto getMemoryAccess = [](MemIntrinsic *MI)->std::vector<SPIRVWord> {
- std::vector<SPIRVWord> MemoryAccess(1, MemoryAccessMaskNone);
- if (SPIRVWord AlignVal = MI->getDestAlignment()) {
- MemoryAccess[0] |= MemoryAccessAlignedMask;
- MemoryAccess.push_back(AlignVal);
- }
- if (MI->isVolatile())
- MemoryAccess[0] |= MemoryAccessVolatileMask;
- return MemoryAccess;
- };
-
- switch (II->getIntrinsicID()) {
- case Intrinsic::fmuladd : {
- // For llvm.fmuladd.* fusion is not guaranteed. If a fused multiply-add
- // is required the corresponding llvm.fma.* intrinsic function should be
- // used instead.
- SPIRVType *Ty = transType(II->getType());
- SPIRVValue *Mul = BM->addBinaryInst(OpFMul, Ty,
- transValue(II->getArgOperand(0), BB),
- transValue(II->getArgOperand(1), BB),
- BB);
- return BM->addBinaryInst(OpFAdd, Ty, Mul,
- transValue(II->getArgOperand(2), BB), BB);
- }
- case Intrinsic::memset : {
- // Generally memset can't be translated with current version of SPIRV spec.
- // But in most cases it turns out that memset is emited by Clang to do
- // zero-initializtion in default constructors.
- // The code below handles only cases with val = 0 and constant len.
- MemSetInst *MSI = cast<MemSetInst>(II);
- Value *Val = MSI->getValue();
- if (!isa<Constant>(Val)) {
- assert(!"Can't translate llvm.memset with non-const `value` argument");
- return nullptr;
- }
- if (!cast<Constant>(Val)->isZeroValue()) {
- assert(!"Can't translate llvm.memset with non-zero `value` argument");
- return nullptr;
- }
- Value *Len = MSI->getLength();
- if (!isa<ConstantInt>(Len)) {
- assert(!"Can't translate llvm.memset with non-const `length` argument");
- return nullptr;
- }
- uint64_t NumElements = static_cast<ConstantInt*>(Len)->getZExtValue();
- auto *AT = ArrayType::get(Val->getType(), NumElements);
- SPIRVTypeArray *CompositeTy = static_cast<SPIRVTypeArray*>(transType(AT));
- SPIRVValue *Init = BM->addNullConstant(CompositeTy);
- SPIRVType *VarTy = transType(PointerType::get(AT, SPIRV::SPIRAS_Constant));
- SPIRVValue *Var = BM->addVariable(VarTy,/*isConstant*/true,
- spv::LinkageTypeInternal, Init, "",
- StorageClassUniformConstant, nullptr);
- SPIRVType *SourceTy = transType(PointerType::get(Val->getType(),
- SPIRV::SPIRAS_Constant));
- SPIRVValue *Source = BM->addUnaryInst(OpBitcast, SourceTy, Var, BB);
- SPIRVValue *Target = transValue(MSI->getRawDest(), BB);
- return BM->addCopyMemorySizedInst(Target, Source, CompositeTy->getLength(),
- getMemoryAccess(MSI), BB);
- } break;
- case Intrinsic::memcpy:
- assert(cast<MemCpyInst>(II)->getSourceAlignment() ==
- cast<MemCpyInst>(II)->getDestAlignment() && "Alignment mismatch!");
- return BM->addCopyMemorySizedInst(
- transValue(II->getOperand(0), BB),
- transValue(II->getOperand(1), BB),
- transValue(II->getOperand(2), BB),
- getMemoryAccess(cast<MemIntrinsic>(II)),
- BB);
- case Intrinsic::lifetime_start:
- return transLifetimeIntrinsicInst(OpLifetimeStart, II, BB);
- case Intrinsic::lifetime_end:
- return transLifetimeIntrinsicInst(OpLifetimeStop, II, BB);
- default:
- // LLVM intrinsic functions shouldn't get to SPIRV, because they
- // would have no definition there.
- BM->getErrorLog().checkError(false, SPIRVEC_InvalidFunctionCall,
- II->getName().str(), "", __FILE__, __LINE__);
- }
- return nullptr;
-}
-
-SPIRVValue *
-LLVMToSPIRV::transCallInst(CallInst *CI, SPIRVBasicBlock *BB) {
- SPIRVExtInstSetKind ExtSetKind = SPIRVEIS_Count;
- SPIRVWord ExtOp = SPIRVWORD_MAX;
- llvm::Function* F = CI->getCalledFunction();
- auto MangledName = F->getName();
- std::string DemangledName;
-
- if (MangledName.startswith(SPCV_CAST))
- return transSpcvCast(CI, BB);
-
- if (oclIsBuiltin(MangledName, &DemangledName) ||
- isDecoratedSPIRVFunc(F, &DemangledName))
- if (auto BV = transBuiltinToInst(DemangledName, MangledName, CI, BB))
- return BV;
-
- SmallVector<std::string, 2> Dec;
- if (isBuiltinTransToExtInst(CI->getCalledFunction(), &ExtSetKind,
- &ExtOp, &Dec))
- return addDecorations(BM->addExtInst(
- transType(CI->getType()),
- ExtSetId,
- ExtOp,
- transArguments(CI, BB, SPIRVEntry::create_unique(ExtSetKind, ExtOp).get()),
- BB), Dec);
-
- return BM->addCallInst(
- transFunctionDecl(CI->getCalledFunction()),
- transArguments(CI, BB, SPIRVEntry::create_unique(OpFunctionCall).get()),
- BB);
-}
-
-bool
-LLVMToSPIRV::transAddressingMode() {
- Triple TargetTriple(M->getTargetTriple());
- Triple::ArchType Arch = TargetTriple.getArch();
-
- SPIRVCKRT(Arch == Triple::spir || Arch == Triple::spir64,
- InvalidTargetTriple,
- "Actual target triple is " + M->getTargetTriple());
-
- if (Arch == Triple::spir)
- BM->setAddressingModel(AddressingModelPhysical32);
- else
- BM->setAddressingModel(AddressingModelPhysical64);
- // Physical addressing model requires Addresses capability
- BM->addCapability(CapabilityAddresses);
- return true;
-}
-std::vector<SPIRVValue*>
-LLVMToSPIRV::transValue(const std::vector<Value *> &Args, SPIRVBasicBlock* BB) {
- std::vector<SPIRVValue*> BArgs;
- for (auto &I: Args)
- BArgs.push_back(transValue(I, BB));
- return BArgs;
-}
-
-std::vector<SPIRVValue*>
-LLVMToSPIRV::transArguments(CallInst *CI, SPIRVBasicBlock *BB) {
- return transValue(getArguments(CI), BB);
-}
-
-std::vector<SPIRVWord>
-LLVMToSPIRV::transValue(const std::vector<Value *> &Args, SPIRVBasicBlock* BB,
- SPIRVEntry *Entry) {
- std::vector<SPIRVWord> Operands;
- for (size_t I = 0, E = Args.size(); I != E; ++I) {
- Operands.push_back(Entry->isOperandLiteral(I) ?
- cast<ConstantInt>(Args[I])->getZExtValue() :
- transValue(Args[I], BB)->getId());
- }
- return Operands;
-}
-
-std::vector<SPIRVWord>
-LLVMToSPIRV::transArguments(CallInst *CI, SPIRVBasicBlock *BB, SPIRVEntry *Entry) {
- return transValue(getArguments(CI), BB, Entry);
-}
-
-SPIRVWord
-LLVMToSPIRV::transFunctionControlMask(CallInst *CI) {
- SPIRVWord FCM = 0;
- SPIRSPIRVFuncCtlMaskMap::foreach([&](Attribute::AttrKind Attr,
- SPIRVFunctionControlMaskKind Mask){
- if (CI->hasFnAttr(Attr))
- FCM |= Mask;
- });
- return FCM;
-}
-
-SPIRVWord
-LLVMToSPIRV::transFunctionControlMask(Function *F) {
- SPIRVWord FCM = 0;
- SPIRSPIRVFuncCtlMaskMap::foreach([&](Attribute::AttrKind Attr,
- SPIRVFunctionControlMaskKind Mask){
- if (F->hasFnAttribute(Attr))
- FCM |= Mask;
- });
- return FCM;
-}
-
-bool
-LLVMToSPIRV::transGlobalVariables() {
- for (auto I = M->global_begin(),
- E = M->global_end(); I != E; ++I) {
- if (!transValue(&(*I), nullptr))
- return false;
- }
- return true;
-}
-
-void
-LLVMToSPIRV::mutateFuncArgType(const std::map<unsigned, Type*>& ChangedType,
- Function* F) {
- for (auto &I : ChangedType) {
- for (auto UI = F->user_begin(), UE = F->user_end(); UI != UE; ++UI) {
- auto Call = dyn_cast<CallInst>(*UI);
- if (!Call)
- continue;
- auto Arg = Call->getArgOperand(I.first);
- auto OrigTy = Arg->getType();
- if (OrigTy == I.second)
- continue;
- SPIRVDBG(dbgs() << "[mutate arg type] " << *Call << ", " << *Arg << '\n');
- auto CastF = M->getOrInsertFunction(SPCV_CAST, I.second, OrigTy);
- std::vector<Value *> Args;
- Args.push_back(Arg);
- auto Cast = CallInst::Create(CastF, Args, "", Call);
- Call->replaceUsesOfWith(Arg, Cast);
- SPIRVDBG(dbgs() << "[mutate arg type] -> " << *Cast << '\n');
- }
- }
-}
-
-void
-LLVMToSPIRV::transFunction(Function *I) {
- transFunctionDecl(I);
- // Creating all basic blocks before creating any instruction.
- for (auto &FI:*I) {
- transValue(&FI, nullptr);
- }
- for (auto &FI:*I) {
- SPIRVBasicBlock* BB = static_cast<SPIRVBasicBlock*>(transValue(&FI, nullptr));
- for (auto &BI:FI) {
- transValue(&BI, BB, false);
- }
- }
-}
-
-bool
-LLVMToSPIRV::translate() {
- BM->setGeneratorVer(kTranslatorVer);
-
- if (!transSourceLanguage())
- return false;
- if (!transExtension())
- return false;
- if (!transBuiltinSet())
- return false;
- if (!transAddressingMode())
- return false;
- if (!transGlobalVariables())
- return false;
-
- for (auto &F:*M) {
- auto FT = F.getFunctionType();
- std::map<unsigned, Type *> ChangedType;
- oclGetMutatedArgumentTypesByBuiltin(FT, ChangedType, &F);
- mutateFuncArgType(ChangedType, &F);
- }
-
- // SPIR-V logical layout requires all function declarations go before
- // function definitions.
- std::vector<Function *> Decls, Defs;
- for (auto &F:*M) {
- if (isBuiltinTransToInst(&F) || isBuiltinTransToExtInst(&F)
- || F.getName().startswith(SPCV_CAST) ||
- F.getName().startswith(LLVM_MEMCPY))
- continue;
- if (F.isDeclaration())
- Decls.push_back(&F);
- else
- Defs.push_back(&F);
- }
- for (auto I:Decls)
- transFunctionDecl(I);
- for (auto I:Defs)
- transFunction(I);
-
- if (!transOCLKernelMetadata())
- return false;
- if (!transExecutionMode())
- return false;
-
- BM->optimizeDecorates();
- BM->resolveUnknownStructFields();
- BM->createForwardPointers();
- return true;
-}
-
-llvm::IntegerType* LLVMToSPIRV::getSizetType() {
- return IntegerType::getIntNTy(M->getContext(),
- M->getDataLayout().getPointerSizeInBits());
-}
-
-void
-LLVMToSPIRV::oclGetMutatedArgumentTypesByBuiltin(
- llvm::FunctionType* FT, std::map<unsigned, Type*>& ChangedType,
- Function* F) {
- auto Name = F->getName();
- std::string Demangled;
- if (!oclIsBuiltin(Name, &Demangled))
- return;
- if (Demangled.find(kSPIRVName::SampledImage) == std::string::npos)
- return;
- if (FT->getParamType(1)->isIntegerTy())
- ChangedType[1] = getSamplerType(F->getParent());
-}
-
-SPIRVInstruction *
-LLVMToSPIRV::transBuiltinToInst(const std::string& DemangledName,
- const std::string &MangledName, CallInst* CI, SPIRVBasicBlock* BB) {
- SmallVector<std::string, 2> Dec;
- auto OC = getSPIRVFuncOC(DemangledName, &Dec);
-
- if (OC == OpNop)
- return nullptr;
-
- auto Inst = transBuiltinToInstWithoutDecoration(OC, CI, BB);
- addDecorations(Inst, Dec);
- return Inst;
-}
-
-bool
-LLVMToSPIRV::transExecutionMode() {
- if (auto NMD = SPIRVMDWalker(*M).getNamedMD(kSPIRVMD::ExecutionMode)) {
- while (!NMD.atEnd()) {
- unsigned EMode = ~0U;
- Function *F = nullptr;
- auto N = NMD.nextOp(); /* execution mode MDNode */
- N.get(F).get(EMode);
-
- SPIRVFunction *BF = static_cast<SPIRVFunction *>(getTranslatedValue(F));
- assert(BF && "Invalid kernel function");
- if (!BF)
- return false;
-
- switch (EMode) {
- case spv::ExecutionModeContractionOff:
- case spv::ExecutionModeInitializer:
- case spv::ExecutionModeFinalizer:
- BF->addExecutionMode(new SPIRVExecutionMode(BF,
- static_cast<ExecutionMode>(EMode)));
- break;
- case spv::ExecutionModeLocalSize:
- case spv::ExecutionModeLocalSizeHint: {
- unsigned X, Y, Z;
- N.get(X).get(Y).get(Z);
- BF->addExecutionMode(new SPIRVExecutionMode(BF,
- static_cast<ExecutionMode>(EMode), X, Y, Z));
- }
- break;
- case spv::ExecutionModeVecTypeHint:
- case spv::ExecutionModeSubgroupSize:
- case spv::ExecutionModeSubgroupsPerWorkgroup: {
- unsigned X;
- N.get(X);
- BF->addExecutionMode(new SPIRVExecutionMode(BF,
- static_cast<ExecutionMode>(EMode), X));
- }
- break;
- default:
- llvm_unreachable("invalid execution mode");
- }
- }
- }
- return true;
-}
-
-bool
-LLVMToSPIRV::transOCLKernelMetadata() {
- NamedMDNode *KernelMDs = M->getNamedMetadata(SPIR_MD_KERNELS);
- std::vector<std::string> argAccessQual;
- if (!KernelMDs)
- return true;
-
- for (unsigned I = 0, E = KernelMDs->getNumOperands(); I < E; ++I) {
- MDNode *KernelMD = KernelMDs->getOperand(I);
- if (KernelMD->getNumOperands() == 0)
- continue;
- Function *Kernel = mdconst::dyn_extract<Function>(KernelMD->getOperand(0));
-
- SPIRVFunction *BF = static_cast<SPIRVFunction *>(getTranslatedValue(Kernel));
- assert(BF && "Kernel function should be translated first");
- assert(Kernel && oclIsKernel(Kernel)
- && "Invalid kernel calling convention or metadata");
- for (unsigned MI = 1, ME = KernelMD->getNumOperands(); MI < ME; ++MI) {
- MDNode *MD = dyn_cast<MDNode>(KernelMD->getOperand(MI));
- if (!MD)
- continue;
- MDString *NameMD = dyn_cast<MDString>(MD->getOperand(0));
- if (!NameMD)
- continue;
- StringRef Name = NameMD->getString();
- if (Name == SPIR_MD_KERNEL_ARG_TYPE_QUAL) {
- foreachKernelArgMD(MD, BF,
- [](const std::string &Str, SPIRVFunctionParameter *BA){
- if (Str.find("volatile") != std::string::npos)
- BA->addDecorate(new SPIRVDecorate(DecorationVolatile, BA));
- if (Str.find("restrict") != std::string::npos)
- BA->addDecorate(new SPIRVDecorate(DecorationFuncParamAttr,
- BA, FunctionParameterAttributeNoAlias));
- if (Str.find("const") != std::string::npos)
- BA->addDecorate(new SPIRVDecorate(DecorationFuncParamAttr,
- BA, FunctionParameterAttributeNoWrite));
- });
- } else if (Name == SPIR_MD_KERNEL_ARG_NAME) {
- foreachKernelArgMD(MD, BF,
- [=](const std::string &Str, SPIRVFunctionParameter *BA){
- BM->setName(BA, Str);
- });
- }
- }
- }
- return true;
-}
-
-bool
-LLVMToSPIRV::transSourceLanguage() {
- auto Src = getSPIRVSource(M);
- SrcLang = std::get<0>(Src);
- SrcLangVer = std::get<1>(Src);
- BM->setSourceLanguage(static_cast<SourceLanguage>(SrcLang), SrcLangVer);
- return true;
-}
-
-bool
-LLVMToSPIRV::transExtension() {
- if (auto N = SPIRVMDWalker(*M).getNamedMD(kSPIRVMD::Extension)) {
- while (!N.atEnd()) {
- std::string S;
- N.nextOp().get(S);
- assert(!S.empty() && "Invalid extension");
- BM->getExtension().insert(S);
- }
- }
- if (auto N = SPIRVMDWalker(*M).getNamedMD(kSPIRVMD::SourceExtension)) {
- while (!N.atEnd()) {
- std::string S;
- N.nextOp().get(S);
- assert(!S.empty() && "Invalid extension");
- BM->getSourceExtension().insert(S);
- }
- }
- for (auto &I:map<SPIRVCapabilityKind>(rmap<OclExt::Kind>(BM->getExtension())))
- BM->addCapability(I);
-
- return true;
-}
-
-void
-LLVMToSPIRV::dumpUsers(Value* V) {
- SPIRVDBG(dbgs() << "Users of " << *V << " :\n");
- for (auto UI = V->user_begin(), UE = V->user_end();
- UI != UE; ++UI)
- SPIRVDBG(dbgs() << " " << **UI << '\n');
-}
-
-Op
-LLVMToSPIRV::transBoolOpCode(SPIRVValue* Opn, Op OC) {
- if (!Opn->getType()->isTypeVectorOrScalarBool())
- return OC;
- IntBoolOpMap::find(OC, &OC);
- return OC;
-}
-
-SPIRVInstruction *
-LLVMToSPIRV::transBuiltinToInstWithoutDecoration(Op OC,
- CallInst* CI, SPIRVBasicBlock* BB) {
- if (isGroupOpCode(OC))
- BM->addCapability(CapabilityGroups);
- switch (OC) {
- case OpControlBarrier: {
- auto BArgs = transValue(getArguments(CI), BB);
- return BM->addControlBarrierInst(
- BArgs[0], BArgs[1], BArgs[2], BB);
- }
- break;
- case OpGroupAsyncCopy: {
- auto BArgs = transValue(getArguments(CI), BB);
- return BM->addAsyncGroupCopy(BArgs[0], BArgs[1], BArgs[2], BArgs[3],
- BArgs[4], BArgs[5], BB);
- }
- break;
- case OpSelect: {
- auto BArgs = transValue(getArguments(CI), BB);
- return BM->addSelectInst(BArgs[0], BArgs[1], BArgs[2], BB);
- }
- default: {
- if (isCvtOpCode(OC) && OC != OpGenericCastToPtrExplicit) {
- return BM->addUnaryInst(OC, transType(CI->getType()),
- transValue(CI->getArgOperand(0), BB), BB);
- } else if (isCmpOpCode(OC)) {
- assert(CI && CI->getNumArgOperands() == 2 && "Invalid call inst");
- auto ResultTy = CI->getType();
- Type *BoolTy = IntegerType::getInt1Ty(M->getContext());
- auto IsVector = ResultTy->isVectorTy();
- if (IsVector)
- BoolTy = VectorType::get(BoolTy, ResultTy->getVectorNumElements());
- auto BBT = transType(BoolTy);
- auto Cmp = BM->addCmpInst(OC, BBT,
- transValue(CI->getArgOperand(0), BB),
- transValue(CI->getArgOperand(1), BB), BB);
- // OpenCL C and OpenCL C++ built-ins may have different return type
- if (ResultTy == BoolTy)
- return Cmp;
- assert(IsVector || (!IsVector && ResultTy->isIntegerTy(32)));
- auto Zero = transValue(Constant::getNullValue(ResultTy), BB);
- auto One = transValue(
- IsVector ? Constant::getAllOnesValue(ResultTy) : getInt32(M, 1), BB);
- return BM->addSelectInst(Cmp, One, Zero, BB);
- } else if (isBinaryOpCode(OC)) {
- assert(CI && CI->getNumArgOperands() == 2 && "Invalid call inst");
- return BM->addBinaryInst(OC, transType(CI->getType()),
- transValue(CI->getArgOperand(0), BB),
- transValue(CI->getArgOperand(1), BB), BB);
- } else if (CI->getNumArgOperands() == 1 &&
- !CI->getType()->isVoidTy() &&
- !hasExecScope(OC) &&
- !isAtomicOpCode(OC)) {
- return BM->addUnaryInst(OC, transType(CI->getType()),
- transValue(CI->getArgOperand(0), BB), BB);
- } else {
- auto Args = getArguments(CI);
- SPIRVType *SPRetTy = nullptr;
- Type *RetTy = CI->getType();
- auto F = CI->getCalledFunction();
- if (!RetTy->isVoidTy()) {
- SPRetTy = transType(RetTy);
- } else if (Args.size() > 0 && F->arg_begin()->hasStructRetAttr()) {
- SPRetTy = transType(F->arg_begin()->getType()->getPointerElementType());
- Args.erase(Args.begin());
- }
- auto SPI = BM->addInstTemplate(OC, BB, SPRetTy);
- std::vector<SPIRVWord> SPArgs;
- for (size_t I = 0, E = Args.size(); I != E; ++I) {
- assert((!isFunctionPointerType(Args[I]->getType()) ||
- isa<Function>(Args[I])) &&
- "Invalid function pointer argument");
- SPArgs.push_back(SPI->isOperandLiteral(I) ?
- cast<ConstantInt>(Args[I])->getZExtValue() :
- transValue(Args[I], BB)->getId());
- }
- SPI->setOpWordsAndValidate(SPArgs);
- if (!SPRetTy || !SPRetTy->isTypeStruct())
- return SPI;
- std::vector<SPIRVWord> Mem;
- SPIRVDBG(spvdbgs() << *SPI << '\n');
- return BM->addStoreInst(transValue(CI->getArgOperand(0), BB), SPI,
- Mem, BB);
- }
- }
- }
- return nullptr;
-}
-
-
-SPIRVId
-LLVMToSPIRV::addInt32(int I) {
- return transValue(getInt32(M, I), nullptr, false)->getId();
-}
-
-SPIRV::SPIRVLinkageTypeKind
-LLVMToSPIRV::transLinkageType(const GlobalValue* GV) {
- if(GV->isDeclarationForLinker())
- return SPIRVLinkageTypeKind::LinkageTypeImport;
- if(GV->hasInternalLinkage() || GV->hasPrivateLinkage())
- return SPIRVLinkageTypeKind::LinkageTypeInternal;
- return SPIRVLinkageTypeKind::LinkageTypeExport;
-}
-} // end of SPIRV namespace
-
-char LLVMToSPIRV::ID = 0;
-
-INITIALIZE_PASS_BEGIN(LLVMToSPIRV, "llvmtospv", "Translate LLVM to SPIR-V",
- false, false)
-INITIALIZE_PASS_DEPENDENCY(OCLTypeToSPIRV)
-INITIALIZE_PASS_END(LLVMToSPIRV, "llvmtospv", "Translate LLVM to SPIR-V",
- false, false)
-
-ModulePass *llvm::createLLVMToSPIRV(SPIRVModule *SMod) {
- return new LLVMToSPIRV(SMod);
-}
-
-void
-addPassesForSPIRV(legacy::PassManager &PassMgr) {
- if (SPIRVMemToReg)
- PassMgr.add(createPromoteMemoryToRegisterPass());
- PassMgr.add(createTransOCLMD());
- PassMgr.add(createOCL21ToSPIRV());
- PassMgr.add(createSPIRVLowerOCLBlocks());
- PassMgr.add(createOCLTypeToSPIRV());
- PassMgr.add(createOCL20ToSPIRV());
- PassMgr.add(createSPIRVRegularizeLLVM());
- PassMgr.add(createSPIRVLowerConstExpr());
- PassMgr.add(createSPIRVLowerBool());
- PassMgr.add(createSPIRVLowerMemmove());
-}
-
-bool
-llvm::WriteSPIRV(Module *M, llvm::raw_ostream &OS, std::string &ErrMsg) {
- std::unique_ptr<SPIRVModule> BM(SPIRVModule::createSPIRVModule());
- legacy::PassManager PassMgr;
- addPassesForSPIRV(PassMgr);
- PassMgr.add(createLLVMToSPIRV(BM.get()));
- PassMgr.run(*M);
-
- if (BM->getError(ErrMsg) != SPIRVEC_Success)
- return false;
- OS << *BM;
- return true;
-}
-
-bool
-llvm::RegularizeLLVMForSPIRV(Module *M, std::string &ErrMsg) {
- std::unique_ptr<SPIRVModule> BM(SPIRVModule::createSPIRVModule());
- legacy::PassManager PassMgr;
- addPassesForSPIRV(PassMgr);
- PassMgr.run(*M);
- return true;
-}
-
+ assert((BM->getSourceLanguage(&Ver) == SourceLanguageOpenCL_C || + BM->getSourceLanguage(&Ver) == SourceLanguageOpenCL_CPP) && + "not supported"); + std::stringstream SS; + SS << "OpenCL.std"; + return BM->importBuiltinSet(SS.str(), &ExtSetId); +} + +/// Transform sampler* spcv.cast(i32 arg) +/// Only two cases are possible: +/// arg = ConstantInt x -> SPIRVConstantSampler +/// arg = i32 argument -> transValue(arg) +/// arg = load from sampler -> look through load +SPIRVValue * +LLVMToSPIRV::oclTransSpvcCastSampler(CallInst* CI, SPIRVBasicBlock *BB) { + llvm::Function* F = CI->getCalledFunction(); + auto FT = F->getFunctionType(); + auto RT = FT->getReturnType(); + assert(FT->getNumParams() == 1); + assert(isSPIRVType(RT, kSPIRVTypeName::Sampler) && + FT->getParamType(0)->isIntegerTy() && "Invalid sampler type"); + auto Arg = CI->getArgOperand(0); + + auto GetSamplerConstant = [&](uint64_t SamplerValue) { + auto AddrMode = (SamplerValue & 0xE) >> 1; + auto Param = SamplerValue & 0x1; + auto Filter = ((SamplerValue & 0x30) >> 4) - 1; + auto BV = BM->addSamplerConstant(transType(RT), AddrMode, Param, Filter); + return BV; + }; + + if (auto Const = dyn_cast<ConstantInt>(Arg)) { + // Sampler is declared as a kernel scope constant + return GetSamplerConstant(Const->getZExtValue()); + } else if (auto Load = dyn_cast<LoadInst>(Arg)) { + // If value of the sampler is loaded from a global constant, use its + // initializer for initialization of the sampler. + auto Op = Load->getPointerOperand(); + assert(isa<GlobalVariable>(Op) && "Unknown sampler pattern!"); + auto GV = cast<GlobalVariable>(Op); + assert(GV->isConstant() || + GV->getType()->getPointerAddressSpace() == SPIRAS_Constant); + auto Initializer = GV->getInitializer(); + assert(isa<ConstantInt>(Initializer) && "sampler not constant int?"); + return GetSamplerConstant(cast<ConstantInt>(Initializer)->getZExtValue()); + } + // Sampler is a function argument + auto BV = transValue(Arg, BB); + assert(BV && BV->getType() == transType(RT)); + return BV; +} + +SPIRVValue * +LLVMToSPIRV::transSpcvCast(CallInst* CI, SPIRVBasicBlock *BB) { + return oclTransSpvcCastSampler(CI, BB); +} + +SPIRVValue * +LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, SPIRVBasicBlock *BB) { + auto getMemoryAccess = [](MemIntrinsic *MI)->std::vector<SPIRVWord> { + std::vector<SPIRVWord> MemoryAccess(1, MemoryAccessMaskNone); + if (SPIRVWord AlignVal = MI->getDestAlignment()) { + MemoryAccess[0] |= MemoryAccessAlignedMask; + MemoryAccess.push_back(AlignVal); + } + if (MI->isVolatile()) + MemoryAccess[0] |= MemoryAccessVolatileMask; + return MemoryAccess; + }; + + switch (II->getIntrinsicID()) { + case Intrinsic::fmuladd : { + // For llvm.fmuladd.* fusion is not guaranteed. If a fused multiply-add + // is required the corresponding llvm.fma.* intrinsic function should be + // used instead. + SPIRVType *Ty = transType(II->getType()); + SPIRVValue *Mul = BM->addBinaryInst(OpFMul, Ty, + transValue(II->getArgOperand(0), BB), + transValue(II->getArgOperand(1), BB), + BB); + return BM->addBinaryInst(OpFAdd, Ty, Mul, + transValue(II->getArgOperand(2), BB), BB); + } + case Intrinsic::memset : { + // Generally memset can't be translated with current version of SPIRV spec. + // But in most cases it turns out that memset is emited by Clang to do + // zero-initializtion in default constructors. + // The code below handles only cases with val = 0 and constant len. + MemSetInst *MSI = cast<MemSetInst>(II); + Value *Val = MSI->getValue(); + if (!isa<Constant>(Val)) { + assert(!"Can't translate llvm.memset with non-const `value` argument"); + return nullptr; + } + if (!cast<Constant>(Val)->isZeroValue()) { + assert(!"Can't translate llvm.memset with non-zero `value` argument"); + return nullptr; + } + Value *Len = MSI->getLength(); + if (!isa<ConstantInt>(Len)) { + assert(!"Can't translate llvm.memset with non-const `length` argument"); + return nullptr; + } + uint64_t NumElements = static_cast<ConstantInt*>(Len)->getZExtValue(); + auto *AT = ArrayType::get(Val->getType(), NumElements); + SPIRVTypeArray *CompositeTy = static_cast<SPIRVTypeArray*>(transType(AT)); + SPIRVValue *Init = BM->addNullConstant(CompositeTy); + SPIRVType *VarTy = transType(PointerType::get(AT, SPIRV::SPIRAS_Constant)); + SPIRVValue *Var = BM->addVariable(VarTy,/*isConstant*/true, + spv::LinkageTypeInternal, Init, "", + StorageClassUniformConstant, nullptr); + SPIRVType *SourceTy = transType(PointerType::get(Val->getType(), + SPIRV::SPIRAS_Constant)); + SPIRVValue *Source = BM->addUnaryInst(OpBitcast, SourceTy, Var, BB); + SPIRVValue *Target = transValue(MSI->getRawDest(), BB); + return BM->addCopyMemorySizedInst(Target, Source, CompositeTy->getLength(), + getMemoryAccess(MSI), BB); + } break; + case Intrinsic::memcpy: + assert(cast<MemCpyInst>(II)->getSourceAlignment() == + cast<MemCpyInst>(II)->getDestAlignment() && "Alignment mismatch!"); + return BM->addCopyMemorySizedInst( + transValue(II->getOperand(0), BB), + transValue(II->getOperand(1), BB), + transValue(II->getOperand(2), BB), + getMemoryAccess(cast<MemIntrinsic>(II)), + BB); + case Intrinsic::lifetime_start: + return transLifetimeIntrinsicInst(OpLifetimeStart, II, BB); + case Intrinsic::lifetime_end: + return transLifetimeIntrinsicInst(OpLifetimeStop, II, BB); + default: + // LLVM intrinsic functions shouldn't get to SPIRV, because they + // would have no definition there. + BM->getErrorLog().checkError(false, SPIRVEC_InvalidFunctionCall, + II->getName().str(), "", __FILE__, __LINE__); + } + return nullptr; +} + +SPIRVValue * +LLVMToSPIRV::transCallInst(CallInst *CI, SPIRVBasicBlock *BB) { + SPIRVExtInstSetKind ExtSetKind = SPIRVEIS_Count; + SPIRVWord ExtOp = SPIRVWORD_MAX; + llvm::Function* F = CI->getCalledFunction(); + auto MangledName = F->getName(); + std::string DemangledName; + + if (MangledName.startswith(SPCV_CAST)) + return transSpcvCast(CI, BB); + + if (oclIsBuiltin(MangledName, &DemangledName) || + isDecoratedSPIRVFunc(F, &DemangledName)) + if (auto BV = transBuiltinToInst(DemangledName, MangledName, CI, BB)) + return BV; + + SmallVector<std::string, 2> Dec; + if (isBuiltinTransToExtInst(CI->getCalledFunction(), &ExtSetKind, + &ExtOp, &Dec)) + return addDecorations(BM->addExtInst( + transType(CI->getType()), + ExtSetId, + ExtOp, + transArguments(CI, BB, SPIRVEntry::create_unique(ExtSetKind, ExtOp).get()), + BB), Dec); + + return BM->addCallInst( + transFunctionDecl(CI->getCalledFunction()), + transArguments(CI, BB, SPIRVEntry::create_unique(OpFunctionCall).get()), + BB); +} + +bool +LLVMToSPIRV::transAddressingMode() { + Triple TargetTriple(M->getTargetTriple()); + Triple::ArchType Arch = TargetTriple.getArch(); + + SPIRVCKRT(Arch == Triple::spir || Arch == Triple::spir64, + InvalidTargetTriple, + "Actual target triple is " + M->getTargetTriple()); + + if (Arch == Triple::spir) + BM->setAddressingModel(AddressingModelPhysical32); + else + BM->setAddressingModel(AddressingModelPhysical64); + // Physical addressing model requires Addresses capability + BM->addCapability(CapabilityAddresses); + return true; +} +std::vector<SPIRVValue*> +LLVMToSPIRV::transValue(const std::vector<Value *> &Args, SPIRVBasicBlock* BB) { + std::vector<SPIRVValue*> BArgs; + for (auto &I: Args) + BArgs.push_back(transValue(I, BB)); + return BArgs; +} + +std::vector<SPIRVValue*> +LLVMToSPIRV::transArguments(CallInst *CI, SPIRVBasicBlock *BB) { + return transValue(getArguments(CI), BB); +} + +std::vector<SPIRVWord> +LLVMToSPIRV::transValue(const std::vector<Value *> &Args, SPIRVBasicBlock* BB, + SPIRVEntry *Entry) { + std::vector<SPIRVWord> Operands; + for (size_t I = 0, E = Args.size(); I != E; ++I) { + Operands.push_back(Entry->isOperandLiteral(I) ? + cast<ConstantInt>(Args[I])->getZExtValue() : + transValue(Args[I], BB)->getId()); + } + return Operands; +} + +std::vector<SPIRVWord> +LLVMToSPIRV::transArguments(CallInst *CI, SPIRVBasicBlock *BB, SPIRVEntry *Entry) { + return transValue(getArguments(CI), BB, Entry); +} + +SPIRVWord +LLVMToSPIRV::transFunctionControlMask(CallInst *CI) { + SPIRVWord FCM = 0; + SPIRSPIRVFuncCtlMaskMap::foreach([&](Attribute::AttrKind Attr, + SPIRVFunctionControlMaskKind Mask){ + if (CI->hasFnAttr(Attr)) + FCM |= Mask; + }); + return FCM; +} + +SPIRVWord +LLVMToSPIRV::transFunctionControlMask(Function *F) { + SPIRVWord FCM = 0; + SPIRSPIRVFuncCtlMaskMap::foreach([&](Attribute::AttrKind Attr, + SPIRVFunctionControlMaskKind Mask){ + if (F->hasFnAttribute(Attr)) + FCM |= Mask; + }); + return FCM; +} + +bool +LLVMToSPIRV::transGlobalVariables() { + for (auto I = M->global_begin(), + E = M->global_end(); I != E; ++I) { + if (!transValue(&(*I), nullptr)) + return false; + } + return true; +} + +void +LLVMToSPIRV::mutateFuncArgType(const std::map<unsigned, Type*>& ChangedType, + Function* F) { + for (auto &I : ChangedType) { + for (auto UI = F->user_begin(), UE = F->user_end(); UI != UE; ++UI) { + auto Call = dyn_cast<CallInst>(*UI); + if (!Call) + continue; + auto Arg = Call->getArgOperand(I.first); + auto OrigTy = Arg->getType(); + if (OrigTy == I.second) + continue; + SPIRVDBG(dbgs() << "[mutate arg type] " << *Call << ", " << *Arg << '\n'); + auto CastF = M->getOrInsertFunction(SPCV_CAST, I.second, OrigTy); + std::vector<Value *> Args; + Args.push_back(Arg); + auto Cast = CallInst::Create(CastF, Args, "", Call); + Call->replaceUsesOfWith(Arg, Cast); + SPIRVDBG(dbgs() << "[mutate arg type] -> " << *Cast << '\n'); + } + } +} + +void +LLVMToSPIRV::transFunction(Function *I) { + transFunctionDecl(I); + // Creating all basic blocks before creating any instruction. + for (auto &FI:*I) { + transValue(&FI, nullptr); + } + for (auto &FI:*I) { + SPIRVBasicBlock* BB = static_cast<SPIRVBasicBlock*>(transValue(&FI, nullptr)); + for (auto &BI:FI) { + transValue(&BI, BB, false); + } + } +} + +bool +LLVMToSPIRV::translate() { + BM->setGeneratorVer(kTranslatorVer); + + if (!transSourceLanguage()) + return false; + if (!transExtension()) + return false; + if (!transBuiltinSet()) + return false; + if (!transAddressingMode()) + return false; + if (!transGlobalVariables()) + return false; + + for (auto &F:*M) { + auto FT = F.getFunctionType(); + std::map<unsigned, Type *> ChangedType; + oclGetMutatedArgumentTypesByBuiltin(FT, ChangedType, &F); + mutateFuncArgType(ChangedType, &F); + } + + // SPIR-V logical layout requires all function declarations go before + // function definitions. + std::vector<Function *> Decls, Defs; + for (auto &F:*M) { + if (isBuiltinTransToInst(&F) || isBuiltinTransToExtInst(&F) + || F.getName().startswith(SPCV_CAST) || + F.getName().startswith(LLVM_MEMCPY)) + continue; + if (F.isDeclaration()) + Decls.push_back(&F); + else + Defs.push_back(&F); + } + for (auto I:Decls) + transFunctionDecl(I); + for (auto I:Defs) + transFunction(I); + + if (!transOCLKernelMetadata()) + return false; + if (!transExecutionMode()) + return false; + + BM->optimizeDecorates(); + BM->resolveUnknownStructFields(); + BM->createForwardPointers(); + return true; +} + +llvm::IntegerType* LLVMToSPIRV::getSizetType() { + return IntegerType::getIntNTy(M->getContext(), + M->getDataLayout().getPointerSizeInBits()); +} + +void +LLVMToSPIRV::oclGetMutatedArgumentTypesByBuiltin( + llvm::FunctionType* FT, std::map<unsigned, Type*>& ChangedType, + Function* F) { + auto Name = F->getName(); + std::string Demangled; + if (!oclIsBuiltin(Name, &Demangled)) + return; + if (Demangled.find(kSPIRVName::SampledImage) == std::string::npos) + return; + if (FT->getParamType(1)->isIntegerTy()) + ChangedType[1] = getSamplerType(F->getParent()); +} + +SPIRVInstruction * +LLVMToSPIRV::transBuiltinToInst(const std::string& DemangledName, + const std::string &MangledName, CallInst* CI, SPIRVBasicBlock* BB) { + SmallVector<std::string, 2> Dec; + auto OC = getSPIRVFuncOC(DemangledName, &Dec); + + if (OC == OpNop) + return nullptr; + + auto Inst = transBuiltinToInstWithoutDecoration(OC, CI, BB); + addDecorations(Inst, Dec); + return Inst; +} + +bool +LLVMToSPIRV::transExecutionMode() { + if (auto NMD = SPIRVMDWalker(*M).getNamedMD(kSPIRVMD::ExecutionMode)) { + while (!NMD.atEnd()) { + unsigned EMode = ~0U; + Function *F = nullptr; + auto N = NMD.nextOp(); /* execution mode MDNode */ + N.get(F).get(EMode); + + SPIRVFunction *BF = static_cast<SPIRVFunction *>(getTranslatedValue(F)); + assert(BF && "Invalid kernel function"); + if (!BF) + return false; + + switch (EMode) { + case spv::ExecutionModeContractionOff: + case spv::ExecutionModeInitializer: + case spv::ExecutionModeFinalizer: + BF->addExecutionMode(new SPIRVExecutionMode(BF, + static_cast<ExecutionMode>(EMode))); + break; + case spv::ExecutionModeLocalSize: + case spv::ExecutionModeLocalSizeHint: { + unsigned X, Y, Z; + N.get(X).get(Y).get(Z); + BF->addExecutionMode(new SPIRVExecutionMode(BF, + static_cast<ExecutionMode>(EMode), X, Y, Z)); + } + break; + case spv::ExecutionModeVecTypeHint: + case spv::ExecutionModeSubgroupSize: + case spv::ExecutionModeSubgroupsPerWorkgroup: { + unsigned X; + N.get(X); + BF->addExecutionMode(new SPIRVExecutionMode(BF, + static_cast<ExecutionMode>(EMode), X)); + } + break; + default: + llvm_unreachable("invalid execution mode"); + } + } + } + return true; +} + +bool +LLVMToSPIRV::transOCLKernelMetadata() { + NamedMDNode *KernelMDs = M->getNamedMetadata(SPIR_MD_KERNELS); + std::vector<std::string> argAccessQual; + if (!KernelMDs) + return true; + + for (unsigned I = 0, E = KernelMDs->getNumOperands(); I < E; ++I) { + MDNode *KernelMD = KernelMDs->getOperand(I); + if (KernelMD->getNumOperands() == 0) + continue; + Function *Kernel = mdconst::dyn_extract<Function>(KernelMD->getOperand(0)); + + SPIRVFunction *BF = static_cast<SPIRVFunction *>(getTranslatedValue(Kernel)); + assert(BF && "Kernel function should be translated first"); + assert(Kernel && oclIsKernel(Kernel) + && "Invalid kernel calling convention or metadata"); + for (unsigned MI = 1, ME = KernelMD->getNumOperands(); MI < ME; ++MI) { + MDNode *MD = dyn_cast<MDNode>(KernelMD->getOperand(MI)); + if (!MD) + continue; + MDString *NameMD = dyn_cast<MDString>(MD->getOperand(0)); + if (!NameMD) + continue; + StringRef Name = NameMD->getString(); + if (Name == SPIR_MD_KERNEL_ARG_TYPE_QUAL) { + foreachKernelArgMD(MD, BF, + [](const std::string &Str, SPIRVFunctionParameter *BA){ + if (Str.find("volatile") != std::string::npos) + BA->addDecorate(new SPIRVDecorate(DecorationVolatile, BA)); + if (Str.find("restrict") != std::string::npos) + BA->addDecorate(new SPIRVDecorate(DecorationFuncParamAttr, + BA, FunctionParameterAttributeNoAlias)); + if (Str.find("const") != std::string::npos) + BA->addDecorate(new SPIRVDecorate(DecorationFuncParamAttr, + BA, FunctionParameterAttributeNoWrite)); + }); + } else if (Name == SPIR_MD_KERNEL_ARG_NAME) { + foreachKernelArgMD(MD, BF, + [=](const std::string &Str, SPIRVFunctionParameter *BA){ + BM->setName(BA, Str); + }); + } + } + } + return true; +} + +bool +LLVMToSPIRV::transSourceLanguage() { + auto Src = getSPIRVSource(M); + SrcLang = std::get<0>(Src); + SrcLangVer = std::get<1>(Src); + BM->setSourceLanguage(static_cast<SourceLanguage>(SrcLang), SrcLangVer); + return true; +} + +bool +LLVMToSPIRV::transExtension() { + if (auto N = SPIRVMDWalker(*M).getNamedMD(kSPIRVMD::Extension)) { + while (!N.atEnd()) { + std::string S; + N.nextOp().get(S); + assert(!S.empty() && "Invalid extension"); + BM->getExtension().insert(S); + } + } + if (auto N = SPIRVMDWalker(*M).getNamedMD(kSPIRVMD::SourceExtension)) { + while (!N.atEnd()) { + std::string S; + N.nextOp().get(S); + assert(!S.empty() && "Invalid extension"); + BM->getSourceExtension().insert(S); + } + } + for (auto &I:map<SPIRVCapabilityKind>(rmap<OclExt::Kind>(BM->getExtension()))) + BM->addCapability(I); + + return true; +} + +void +LLVMToSPIRV::dumpUsers(Value* V) { + SPIRVDBG(dbgs() << "Users of " << *V << " :\n"); + for (auto UI = V->user_begin(), UE = V->user_end(); + UI != UE; ++UI) + SPIRVDBG(dbgs() << " " << **UI << '\n'); +} + +Op +LLVMToSPIRV::transBoolOpCode(SPIRVValue* Opn, Op OC) { + if (!Opn->getType()->isTypeVectorOrScalarBool()) + return OC; + IntBoolOpMap::find(OC, &OC); + return OC; +} + +SPIRVInstruction * +LLVMToSPIRV::transBuiltinToInstWithoutDecoration(Op OC, + CallInst* CI, SPIRVBasicBlock* BB) { + if (isGroupOpCode(OC)) + BM->addCapability(CapabilityGroups); + switch (OC) { + case OpControlBarrier: { + auto BArgs = transValue(getArguments(CI), BB); + return BM->addControlBarrierInst( + BArgs[0], BArgs[1], BArgs[2], BB); + } + break; + case OpGroupAsyncCopy: { + auto BArgs = transValue(getArguments(CI), BB); + return BM->addAsyncGroupCopy(BArgs[0], BArgs[1], BArgs[2], BArgs[3], + BArgs[4], BArgs[5], BB); + } + break; + case OpSelect: { + auto BArgs = transValue(getArguments(CI), BB); + return BM->addSelectInst(BArgs[0], BArgs[1], BArgs[2], BB); + } + default: { + if (isCvtOpCode(OC) && OC != OpGenericCastToPtrExplicit) { + return BM->addUnaryInst(OC, transType(CI->getType()), + transValue(CI->getArgOperand(0), BB), BB); + } else if (isCmpOpCode(OC)) { + assert(CI && CI->getNumArgOperands() == 2 && "Invalid call inst"); + auto ResultTy = CI->getType(); + Type *BoolTy = IntegerType::getInt1Ty(M->getContext()); + auto IsVector = ResultTy->isVectorTy(); + if (IsVector) + BoolTy = VectorType::get(BoolTy, ResultTy->getVectorNumElements()); + auto BBT = transType(BoolTy); + auto Cmp = BM->addCmpInst(OC, BBT, + transValue(CI->getArgOperand(0), BB), + transValue(CI->getArgOperand(1), BB), BB); + // OpenCL C and OpenCL C++ built-ins may have different return type + if (ResultTy == BoolTy) + return Cmp; + assert(IsVector || (!IsVector && ResultTy->isIntegerTy(32))); + auto Zero = transValue(Constant::getNullValue(ResultTy), BB); + auto One = transValue( + IsVector ? Constant::getAllOnesValue(ResultTy) : getInt32(M, 1), BB); + return BM->addSelectInst(Cmp, One, Zero, BB); + } else if (isBinaryOpCode(OC)) { + assert(CI && CI->getNumArgOperands() == 2 && "Invalid call inst"); + return BM->addBinaryInst(OC, transType(CI->getType()), + transValue(CI->getArgOperand(0), BB), + transValue(CI->getArgOperand(1), BB), BB); + } else if (CI->getNumArgOperands() == 1 && + !CI->getType()->isVoidTy() && + !hasExecScope(OC) && + !isAtomicOpCode(OC)) { + return BM->addUnaryInst(OC, transType(CI->getType()), + transValue(CI->getArgOperand(0), BB), BB); + } else { + auto Args = getArguments(CI); + SPIRVType *SPRetTy = nullptr; + Type *RetTy = CI->getType(); + auto F = CI->getCalledFunction(); + if (!RetTy->isVoidTy()) { + SPRetTy = transType(RetTy); + } else if (Args.size() > 0 && F->arg_begin()->hasStructRetAttr()) { + SPRetTy = transType(F->arg_begin()->getType()->getPointerElementType()); + Args.erase(Args.begin()); + } + auto SPI = BM->addInstTemplate(OC, BB, SPRetTy); + std::vector<SPIRVWord> SPArgs; + for (size_t I = 0, E = Args.size(); I != E; ++I) { + assert((!isFunctionPointerType(Args[I]->getType()) || + isa<Function>(Args[I])) && + "Invalid function pointer argument"); + SPArgs.push_back(SPI->isOperandLiteral(I) ? + cast<ConstantInt>(Args[I])->getZExtValue() : + transValue(Args[I], BB)->getId()); + } + SPI->setOpWordsAndValidate(SPArgs); + if (!SPRetTy || !SPRetTy->isTypeStruct()) + return SPI; + std::vector<SPIRVWord> Mem; + SPIRVDBG(spvdbgs() << *SPI << '\n'); + return BM->addStoreInst(transValue(CI->getArgOperand(0), BB), SPI, + Mem, BB); + } + } + } + return nullptr; +} + + +SPIRVId +LLVMToSPIRV::addInt32(int I) { + return transValue(getInt32(M, I), nullptr, false)->getId(); +} + +SPIRV::SPIRVLinkageTypeKind +LLVMToSPIRV::transLinkageType(const GlobalValue* GV) { + if(GV->isDeclarationForLinker()) + return SPIRVLinkageTypeKind::LinkageTypeImport; + if(GV->hasInternalLinkage() || GV->hasPrivateLinkage()) + return SPIRVLinkageTypeKind::LinkageTypeInternal; + return SPIRVLinkageTypeKind::LinkageTypeExport; +} +} // end of SPIRV namespace + +char LLVMToSPIRV::ID = 0; + +INITIALIZE_PASS_BEGIN(LLVMToSPIRV, "llvmtospv", "Translate LLVM to SPIR-V", + false, false) +INITIALIZE_PASS_DEPENDENCY(OCLTypeToSPIRV) +INITIALIZE_PASS_END(LLVMToSPIRV, "llvmtospv", "Translate LLVM to SPIR-V", + false, false) + +ModulePass *llvm::createLLVMToSPIRV(SPIRVModule *SMod) { + return new LLVMToSPIRV(SMod); +} + +void +addPassesForSPIRV(legacy::PassManager &PassMgr) { + if (SPIRVMemToReg) + PassMgr.add(createPromoteMemoryToRegisterPass()); + PassMgr.add(createTransOCLMD()); + PassMgr.add(createOCL21ToSPIRV()); + PassMgr.add(createSPIRVLowerOCLBlocks()); + PassMgr.add(createOCLTypeToSPIRV()); + PassMgr.add(createOCL20ToSPIRV()); + PassMgr.add(createSPIRVRegularizeLLVM()); + PassMgr.add(createSPIRVLowerConstExpr()); + PassMgr.add(createSPIRVLowerBool()); + PassMgr.add(createSPIRVLowerMemmove()); +} + +bool +llvm::WriteSPIRV(Module *M, llvm::raw_ostream &OS, std::string &ErrMsg) { + std::unique_ptr<SPIRVModule> BM(SPIRVModule::createSPIRVModule()); + legacy::PassManager PassMgr; + addPassesForSPIRV(PassMgr); + PassMgr.add(createLLVMToSPIRV(BM.get())); + PassMgr.run(*M); + + if (BM->getError(ErrMsg) != SPIRVEC_Success) + return false; + OS << *BM; + return true; +} + +bool +llvm::RegularizeLLVMForSPIRV(Module *M, std::string &ErrMsg) { + std::unique_ptr<SPIRVModule> BM(SPIRVModule::createSPIRVModule()); + legacy::PassManager PassMgr; + addPassesForSPIRV(PassMgr); + PassMgr.run(*M); + return true; +} + diff --git a/lib/SPIRV/libSPIRV/SPIRVBasicBlock.cpp b/lib/SPIRV/libSPIRV/SPIRVBasicBlock.cpp index acdea98..f43724b 100644 --- a/lib/SPIRV/libSPIRV/SPIRVBasicBlock.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVBasicBlock.cpp @@ -1,85 +1,85 @@ -//===- SPIRVBasicBlock.cpp - SPIR-V Basic Block ------------------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file implements SPIRV basic block.
-///
-//===----------------------------------------------------------------------===//
-
-#include "SPIRVEntry.h"
-#include "SPIRVValue.h"
-#include "SPIRVBasicBlock.h"
-#include "SPIRVInstruction.h"
-#include "SPIRVFunction.h"
-#include "SPIRVStream.h"
-
-#include <iostream>
-
-using namespace SPIRV;
-
-SPIRVBasicBlock::SPIRVBasicBlock(SPIRVId TheId, SPIRVFunction *Func)
- :SPIRVValue(Func->getModule(), 2, OpLabel, TheId), ParentF(Func) {
- setAttr();
- validate();
-}
-
-SPIRVDecoder
-SPIRVBasicBlock::getDecoder(std::istream &IS){
- return SPIRVDecoder(IS, *this);
-}
-
-/// Assume I contains valid Id.
-SPIRVInstruction *
-SPIRVBasicBlock::addInstruction(SPIRVInstruction *I) {
- assert(I && "Invalid instruction");
- Module->add(I);
- I->setParent(this);
- InstVec.push_back(I);
- return I;
-}
-
-void
-SPIRVBasicBlock::encodeChildren(spv_ostream &O) const {
- O << SPIRVNL();
- for (size_t i = 0, e = InstVec.size(); i != e; ++i)
- O << *InstVec[i];
-}
-
-_SPIRV_IMP_ENCDEC1(SPIRVBasicBlock, Id)
-
-void
-SPIRVBasicBlock::setScope(SPIRVEntry *Scope) {
- assert(Scope && Scope->getOpCode() == OpFunction && "Invalid scope");
- setParent(static_cast<SPIRVFunction*>(Scope));
-}
+//===- SPIRVBasicBlock.cpp - SPIR-V Basic Block ------------------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file implements SPIRV basic block. +/// +//===----------------------------------------------------------------------===// + +#include "SPIRVEntry.h" +#include "SPIRVValue.h" +#include "SPIRVBasicBlock.h" +#include "SPIRVInstruction.h" +#include "SPIRVFunction.h" +#include "SPIRVStream.h" + +#include <iostream> + +using namespace SPIRV; + +SPIRVBasicBlock::SPIRVBasicBlock(SPIRVId TheId, SPIRVFunction *Func) + :SPIRVValue(Func->getModule(), 2, OpLabel, TheId), ParentF(Func) { + setAttr(); + validate(); +} + +SPIRVDecoder +SPIRVBasicBlock::getDecoder(std::istream &IS){ + return SPIRVDecoder(IS, *this); +} + +/// Assume I contains valid Id. +SPIRVInstruction * +SPIRVBasicBlock::addInstruction(SPIRVInstruction *I) { + assert(I && "Invalid instruction"); + Module->add(I); + I->setParent(this); + InstVec.push_back(I); + return I; +} + +void +SPIRVBasicBlock::encodeChildren(spv_ostream &O) const { + O << SPIRVNL(); + for (size_t i = 0, e = InstVec.size(); i != e; ++i) + O << *InstVec[i]; +} + +_SPIRV_IMP_ENCDEC1(SPIRVBasicBlock, Id) + +void +SPIRVBasicBlock::setScope(SPIRVEntry *Scope) { + assert(Scope && Scope->getOpCode() == OpFunction && "Invalid scope"); + setParent(static_cast<SPIRVFunction*>(Scope)); +} diff --git a/lib/SPIRV/libSPIRV/SPIRVBasicBlock.h b/lib/SPIRV/libSPIRV/SPIRVBasicBlock.h index 5ed2f9e..3022452 100644 --- a/lib/SPIRV/libSPIRV/SPIRVBasicBlock.h +++ b/lib/SPIRV/libSPIRV/SPIRVBasicBlock.h @@ -1,114 +1,114 @@ -//===- SPIRVBasicBlock.h – SPIR-V Basic Block --------------------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines Basic Block class for SPIR-V.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVBASICBLOCK_HPP_
-#define SPIRVBASICBLOCK_HPP_
-
-#include "SPIRVValue.h"
-#include <algorithm>
-
-namespace SPIRV{
-class SPIRVFunction;
-class SPIRVInstruction;
-class SPIRVDecoder;
-class SPIRVBasicBlock: public SPIRVValue {
-
-public:
- SPIRVBasicBlock(SPIRVId TheId, SPIRVFunction *Func);
-
- SPIRVBasicBlock():SPIRVValue(OpLabel), ParentF(NULL){
- setAttr();
- }
-
- SPIRVDecoder getDecoder(std::istream &IS);
- SPIRVFunction *getParent() const { return ParentF;}
- size_t getNumInst() const { return InstVec.size();}
- SPIRVInstruction *getInst(size_t I) const { return InstVec[I];}
- SPIRVInstruction *getPrevious(const SPIRVInstruction *I) const {
- auto Loc = find(I);
- if (Loc == InstVec.end() || Loc == InstVec.begin())
- return nullptr;
- return *(--Loc);
- }
- SPIRVInstruction *getNext(const SPIRVInstruction *I) const {
- auto Loc = find(I);
- if (Loc == InstVec.end())
- return nullptr;
- ++Loc;
- if (Loc == InstVec.end())
- return nullptr;
- return *Loc;
- }
-
- void setScope(SPIRVEntry *Scope);
- void setParent(SPIRVFunction *F) { ParentF = F;}
- SPIRVInstruction *addInstruction(SPIRVInstruction *I);
- void eraseInstruction(const SPIRVInstruction *I) {
- auto Loc = find(I);
- assert(Loc != InstVec.end());
- InstVec.erase(Loc);
- }
-
- void setAttr() { setHasNoType();}
- _SPIRV_DCL_ENCDEC
- void encodeChildren(spv_ostream &)const;
- void validate()const {
- SPIRVValue::validate();
- assert(ParentF && "Invalid parent function");
- }
-
-private:
- SPIRVFunction *ParentF;
- typedef std::vector<SPIRVInstruction *> SPIRVInstructionVector;
- SPIRVInstructionVector InstVec;
-
- SPIRVInstructionVector::const_iterator find(const SPIRVInstruction *Inst)
- const {
- return std::find(InstVec.begin(), InstVec.end(), Inst);
- }
-
- SPIRVInstructionVector::iterator find(const SPIRVInstruction *Inst) {
- return std::find(InstVec.begin(), InstVec.end(), Inst);
- }
-};
-
-typedef SPIRVBasicBlock SPIRVLabel;
-}
-
-#endif
+//===- SPIRVBasicBlock.h – SPIR-V Basic Block --------------------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines Basic Block class for SPIR-V. +/// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVBASICBLOCK_HPP_ +#define SPIRVBASICBLOCK_HPP_ + +#include "SPIRVValue.h" +#include <algorithm> + +namespace SPIRV{ +class SPIRVFunction; +class SPIRVInstruction; +class SPIRVDecoder; +class SPIRVBasicBlock: public SPIRVValue { + +public: + SPIRVBasicBlock(SPIRVId TheId, SPIRVFunction *Func); + + SPIRVBasicBlock():SPIRVValue(OpLabel), ParentF(NULL){ + setAttr(); + } + + SPIRVDecoder getDecoder(std::istream &IS); + SPIRVFunction *getParent() const { return ParentF;} + size_t getNumInst() const { return InstVec.size();} + SPIRVInstruction *getInst(size_t I) const { return InstVec[I];} + SPIRVInstruction *getPrevious(const SPIRVInstruction *I) const { + auto Loc = find(I); + if (Loc == InstVec.end() || Loc == InstVec.begin()) + return nullptr; + return *(--Loc); + } + SPIRVInstruction *getNext(const SPIRVInstruction *I) const { + auto Loc = find(I); + if (Loc == InstVec.end()) + return nullptr; + ++Loc; + if (Loc == InstVec.end()) + return nullptr; + return *Loc; + } + + void setScope(SPIRVEntry *Scope); + void setParent(SPIRVFunction *F) { ParentF = F;} + SPIRVInstruction *addInstruction(SPIRVInstruction *I); + void eraseInstruction(const SPIRVInstruction *I) { + auto Loc = find(I); + assert(Loc != InstVec.end()); + InstVec.erase(Loc); + } + + void setAttr() { setHasNoType();} + _SPIRV_DCL_ENCDEC + void encodeChildren(spv_ostream &)const; + void validate()const { + SPIRVValue::validate(); + assert(ParentF && "Invalid parent function"); + } + +private: + SPIRVFunction *ParentF; + typedef std::vector<SPIRVInstruction *> SPIRVInstructionVector; + SPIRVInstructionVector InstVec; + + SPIRVInstructionVector::const_iterator find(const SPIRVInstruction *Inst) + const { + return std::find(InstVec.begin(), InstVec.end(), Inst); + } + + SPIRVInstructionVector::iterator find(const SPIRVInstruction *Inst) { + return std::find(InstVec.begin(), InstVec.end(), Inst); + } +}; + +typedef SPIRVBasicBlock SPIRVLabel; +} + +#endif diff --git a/lib/SPIRV/libSPIRV/SPIRVDebug.cpp b/lib/SPIRV/libSPIRV/SPIRVDebug.cpp index 86fbaa6..1a373b6 100644 --- a/lib/SPIRV/libSPIRV/SPIRVDebug.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVDebug.cpp @@ -1,46 +1,46 @@ -//===- SPIRVDebug.cpp - SPIR-V Debug Utility ---------------------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines variables for enabling/disabling SPIR-V debug macro.
-///
-//===----------------------------------------------------------------------===//
-
-#include "SPIRVDebug.h"
-
-using namespace SPIRV;
-
-bool SPIRV::SPIRVDbgEnable = false;
-bool SPIRV::SPIRVDbgAssertOnError = true;
-bool SPIRV::SPIRVDbgErrorMsgIncludesSourceInfo = true;
+//===- SPIRVDebug.cpp - SPIR-V Debug Utility ---------------------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines variables for enabling/disabling SPIR-V debug macro. +/// +//===----------------------------------------------------------------------===// + +#include "SPIRVDebug.h" + +using namespace SPIRV; + +bool SPIRV::SPIRVDbgEnable = false; +bool SPIRV::SPIRVDbgAssertOnError = true; +bool SPIRV::SPIRVDbgErrorMsgIncludesSourceInfo = true; diff --git a/lib/SPIRV/libSPIRV/SPIRVDebug.h b/lib/SPIRV/libSPIRV/SPIRVDebug.h index 61366ad..f0c5cb6 100644 --- a/lib/SPIRV/libSPIRV/SPIRVDebug.h +++ b/lib/SPIRV/libSPIRV/SPIRVDebug.h @@ -1,81 +1,81 @@ -//===- SPIRVDebug.h - SPIR-V Debug Utility -----------------------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines Macros and variables for debugging SPIRV.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVDEBUG_HPP_
-#define SPIRVDEBUG_HPP_
-
-#include "SPIRVUtil.h"
-#ifdef _SPIRV_LLVM_API
-#include "llvm/Support/Debug.h"
-#endif
-#include <iostream>
-
-namespace SPIRV{
-
-#define _SPIRVDBG
-#ifdef _SPIRVDBG
-
-#define SPIRVDBG(x) if(SPIRVDbgEnable) {x;}
-
-// Enable debug output.
-extern bool SPIRVDbgEnable;
-
-// Include source file and line number in error message.
-extern bool SPIRVDbgErrorMsgIncludesSourceInfo;
-
-// Enable assert on error
-extern bool SPIRVDbgAssertOnError;
-
-// Output stream for SPIRV debug information.
-inline spv_ostream &spvdbgs() {
-#ifdef _SPIRV_LLVM_API
- return llvm::dbgs();
-#else
- return std::cerr;
-#endif
-}
-
-#else
-
-#define SPIRVDBG(x)
-
-#endif
-
-}
-#endif /* SPIRVDEBUG_HPP_ */
+//===- SPIRVDebug.h - SPIR-V Debug Utility -----------------------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines Macros and variables for debugging SPIRV. +/// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVDEBUG_HPP_ +#define SPIRVDEBUG_HPP_ + +#include "SPIRVUtil.h" +#ifdef _SPIRV_LLVM_API +#include "llvm/Support/Debug.h" +#endif +#include <iostream> + +namespace SPIRV{ + +#define _SPIRVDBG +#ifdef _SPIRVDBG + +#define SPIRVDBG(x) if(SPIRVDbgEnable) {x;} + +// Enable debug output. +extern bool SPIRVDbgEnable; + +// Include source file and line number in error message. +extern bool SPIRVDbgErrorMsgIncludesSourceInfo; + +// Enable assert on error +extern bool SPIRVDbgAssertOnError; + +// Output stream for SPIRV debug information. +inline spv_ostream &spvdbgs() { +#ifdef _SPIRV_LLVM_API + return llvm::dbgs(); +#else + return std::cerr; +#endif +} + +#else + +#define SPIRVDBG(x) + +#endif + +} +#endif /* SPIRVDEBUG_HPP_ */ diff --git a/lib/SPIRV/libSPIRV/SPIRVDecorate.cpp b/lib/SPIRV/libSPIRV/SPIRVDecorate.cpp index b02c007..1f3e0dd 100644 --- a/lib/SPIRV/libSPIRV/SPIRVDecorate.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVDecorate.cpp @@ -1,238 +1,238 @@ -//===- SPIRVDecorate.cpp -SPIR-V Decorations ---------------------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file implements SPIR-V decorations.
-///
-//===----------------------------------------------------------------------===//
-
-#include "SPIRVDecorate.h"
-#include "SPIRVStream.h"
-#include "SPIRVValue.h"
-#include "SPIRVModule.h"
-
-namespace SPIRV{
-template<class T, class B>
-spv_ostream &
-operator<< (spv_ostream &O, const std::multiset<T *, B>& V) {
- for (auto &I: V)
- O << *I;
- return O;
-}
-
-SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC, SPIRVWord WC,
- Decoration TheDec,
- SPIRVEntry *TheTarget)
- : SPIRVAnnotationGeneric(TheTarget->getModule(), WC, OC,
- TheTarget->getId()),
- Dec(TheDec), Owner(nullptr) {
- validate();
- updateModuleVersion();
-}
-
-SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC, SPIRVWord WC,
- Decoration TheDec,
- SPIRVEntry *TheTarget,
- SPIRVWord V)
- : SPIRVAnnotationGeneric(TheTarget->getModule(), WC, OC,
- TheTarget->getId()),
- Dec(TheDec), Owner(nullptr) {
- Literals.push_back(V);
- validate();
- updateModuleVersion();
-}
-
-SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC)
- :SPIRVAnnotationGeneric(OC), Dec(DecorationRelaxedPrecision), Owner(nullptr){
-}
-
-Decoration
-SPIRVDecorateGeneric::getDecorateKind()const {
- return Dec;
-}
-
-SPIRVWord
-SPIRVDecorateGeneric::getLiteral(size_t i) const {
- assert(i <= Literals.size() && "Out of bounds");
- return Literals[i];
-}
-
-size_t
-SPIRVDecorateGeneric::getLiteralCount() const {
- return Literals.size();
-}
-
-void
-SPIRVDecorate::encode(spv_ostream &O)const {
- SPIRVEncoder Encoder = getEncoder(O);
- Encoder << Target << Dec;
- if ( Dec == DecorationLinkageAttributes )
- SPIRVDecorateLinkageAttr::encodeLiterals(Encoder, Literals);
- else
- Encoder << Literals;
-}
-
-void
-SPIRVDecorate::setWordCount(SPIRVWord Count){
- WordCount = Count;
- Literals.resize(WordCount - FixedWC);
-}
-
-void
-SPIRVDecorate::decode(std::istream &I){
- SPIRVDecoder Decoder = getDecoder(I);
- Decoder >> Target >> Dec;
- if(Dec == DecorationLinkageAttributes)
- SPIRVDecorateLinkageAttr::decodeLiterals(Decoder, Literals);
- else
- Decoder >> Literals;
- getOrCreateTarget()->addDecorate(this);
-}
-
-void
-SPIRVMemberDecorate::encode(spv_ostream &O)const {
- getEncoder(O) << Target << MemberNumber << Dec << Literals;
-}
-
-void
-SPIRVMemberDecorate::setWordCount(SPIRVWord Count){
- WordCount = Count;
- Literals.resize(WordCount - FixedWC);
-}
-
-void
-SPIRVMemberDecorate::decode(std::istream &I){
- getDecoder(I) >> Target >> MemberNumber >> Dec >> Literals;
- getOrCreateTarget()->addMemberDecorate(this);
-}
-
-void
-SPIRVDecorationGroup::encode(spv_ostream &O)const {
- getEncoder(O) << Id;
-}
-
-void
-SPIRVDecorationGroup::decode(std::istream &I){
- getDecoder(I) >> Id;
- Module->addDecorationGroup(this);
-}
-
-void
-SPIRVDecorationGroup::encodeAll(spv_ostream &O) const {
- O << Decorations;
- SPIRVEntry::encodeAll(O);
-}
-
-void
-SPIRVGroupDecorateGeneric::encode(spv_ostream &O)const {
- getEncoder(O) << DecorationGroup << Targets;
-}
-
-void
-SPIRVGroupDecorateGeneric::decode(std::istream &I){
- getDecoder(I) >> DecorationGroup >> Targets;
- Module->addGroupDecorateGeneric(this);
-}
-
-void
-SPIRVGroupDecorate::decorateTargets() {
- for(auto &I:Targets) {
- auto Target = getOrCreate(I);
- for (auto &Dec:DecorationGroup->getDecorations()) {
- assert(Dec->isDecorate());
- Target->addDecorate(static_cast<SPIRVDecorate *const>(Dec));
- }
- }
-}
-
-void
-SPIRVGroupMemberDecorate::decorateTargets() {
- for(auto &I:Targets) {
- auto Target = getOrCreate(I);
- for (auto &Dec:DecorationGroup->getDecorations()) {
- assert(Dec->isMemberDecorate());
- Target->addMemberDecorate(static_cast<SPIRVMemberDecorate*>(Dec));
- }
- }
-}
-
-bool
-SPIRVDecorateGeneric::Comparator::operator()(const SPIRVDecorateGeneric *A,
- const SPIRVDecorateGeneric *B) const {
- auto Action = [=](){
- if (A->getOpCode() < B->getOpCode())
- return true;
- if (A->getOpCode() > B->getOpCode())
- return false;
- if (A->getDecorateKind() < B->getDecorateKind())
- return true;
- if (A->getDecorateKind() > B->getDecorateKind())
- return false;
- if (A->getLiteralCount() < B->getLiteralCount())
- return true;
- if (A->getLiteralCount() > B->getLiteralCount())
- return false;
- for (size_t I = 0, E = A->getLiteralCount(); I != E; ++I) {
- auto EA = A->getLiteral(I);
- auto EB = B->getLiteral(I);
- if (EA < EB)
- return true;
- if (EA > EB)
- return false;
- }
- return false;
- };
- auto Res = Action();
- return Res;
-}
-
-bool operator==(const SPIRVDecorateGeneric &A, const SPIRVDecorateGeneric &B) {
- if (A.getTargetId() != B.getTargetId())
- return false;
- if (A.getOpCode() != B.getOpCode())
- return false;
- if (A.getDecorateKind() != B.getDecorateKind())
- return false;
- if (A.getLiteralCount() != B.getLiteralCount())
- return false;
- for (size_t I = 0, E = A.getLiteralCount(); I != E; ++I) {
- auto EA = A.getLiteral(I);
- auto EB = B.getLiteral(I);
- if (EA != EB)
- return false;
- }
- return true;
-}
-}
-
+//===- SPIRVDecorate.cpp -SPIR-V Decorations ---------------------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file implements SPIR-V decorations. +/// +//===----------------------------------------------------------------------===// + +#include "SPIRVDecorate.h" +#include "SPIRVStream.h" +#include "SPIRVValue.h" +#include "SPIRVModule.h" + +namespace SPIRV{ +template<class T, class B> +spv_ostream & +operator<< (spv_ostream &O, const std::multiset<T *, B>& V) { + for (auto &I: V) + O << *I; + return O; +} + +SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC, SPIRVWord WC, + Decoration TheDec, + SPIRVEntry *TheTarget) + : SPIRVAnnotationGeneric(TheTarget->getModule(), WC, OC, + TheTarget->getId()), + Dec(TheDec), Owner(nullptr) { + validate(); + updateModuleVersion(); +} + +SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC, SPIRVWord WC, + Decoration TheDec, + SPIRVEntry *TheTarget, + SPIRVWord V) + : SPIRVAnnotationGeneric(TheTarget->getModule(), WC, OC, + TheTarget->getId()), + Dec(TheDec), Owner(nullptr) { + Literals.push_back(V); + validate(); + updateModuleVersion(); +} + +SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC) + :SPIRVAnnotationGeneric(OC), Dec(DecorationRelaxedPrecision), Owner(nullptr){ +} + +Decoration +SPIRVDecorateGeneric::getDecorateKind()const { + return Dec; +} + +SPIRVWord +SPIRVDecorateGeneric::getLiteral(size_t i) const { + assert(i <= Literals.size() && "Out of bounds"); + return Literals[i]; +} + +size_t +SPIRVDecorateGeneric::getLiteralCount() const { + return Literals.size(); +} + +void +SPIRVDecorate::encode(spv_ostream &O)const { + SPIRVEncoder Encoder = getEncoder(O); + Encoder << Target << Dec; + if ( Dec == DecorationLinkageAttributes ) + SPIRVDecorateLinkageAttr::encodeLiterals(Encoder, Literals); + else + Encoder << Literals; +} + +void +SPIRVDecorate::setWordCount(SPIRVWord Count){ + WordCount = Count; + Literals.resize(WordCount - FixedWC); +} + +void +SPIRVDecorate::decode(std::istream &I){ + SPIRVDecoder Decoder = getDecoder(I); + Decoder >> Target >> Dec; + if(Dec == DecorationLinkageAttributes) + SPIRVDecorateLinkageAttr::decodeLiterals(Decoder, Literals); + else + Decoder >> Literals; + getOrCreateTarget()->addDecorate(this); +} + +void +SPIRVMemberDecorate::encode(spv_ostream &O)const { + getEncoder(O) << Target << MemberNumber << Dec << Literals; +} + +void +SPIRVMemberDecorate::setWordCount(SPIRVWord Count){ + WordCount = Count; + Literals.resize(WordCount - FixedWC); +} + +void +SPIRVMemberDecorate::decode(std::istream &I){ + getDecoder(I) >> Target >> MemberNumber >> Dec >> Literals; + getOrCreateTarget()->addMemberDecorate(this); +} + +void +SPIRVDecorationGroup::encode(spv_ostream &O)const { + getEncoder(O) << Id; +} + +void +SPIRVDecorationGroup::decode(std::istream &I){ + getDecoder(I) >> Id; + Module->addDecorationGroup(this); +} + +void +SPIRVDecorationGroup::encodeAll(spv_ostream &O) const { + O << Decorations; + SPIRVEntry::encodeAll(O); +} + +void +SPIRVGroupDecorateGeneric::encode(spv_ostream &O)const { + getEncoder(O) << DecorationGroup << Targets; +} + +void +SPIRVGroupDecorateGeneric::decode(std::istream &I){ + getDecoder(I) >> DecorationGroup >> Targets; + Module->addGroupDecorateGeneric(this); +} + +void +SPIRVGroupDecorate::decorateTargets() { + for(auto &I:Targets) { + auto Target = getOrCreate(I); + for (auto &Dec:DecorationGroup->getDecorations()) { + assert(Dec->isDecorate()); + Target->addDecorate(static_cast<SPIRVDecorate *const>(Dec)); + } + } +} + +void +SPIRVGroupMemberDecorate::decorateTargets() { + for(auto &I:Targets) { + auto Target = getOrCreate(I); + for (auto &Dec:DecorationGroup->getDecorations()) { + assert(Dec->isMemberDecorate()); + Target->addMemberDecorate(static_cast<SPIRVMemberDecorate*>(Dec)); + } + } +} + +bool +SPIRVDecorateGeneric::Comparator::operator()(const SPIRVDecorateGeneric *A, + const SPIRVDecorateGeneric *B) const { + auto Action = [=](){ + if (A->getOpCode() < B->getOpCode()) + return true; + if (A->getOpCode() > B->getOpCode()) + return false; + if (A->getDecorateKind() < B->getDecorateKind()) + return true; + if (A->getDecorateKind() > B->getDecorateKind()) + return false; + if (A->getLiteralCount() < B->getLiteralCount()) + return true; + if (A->getLiteralCount() > B->getLiteralCount()) + return false; + for (size_t I = 0, E = A->getLiteralCount(); I != E; ++I) { + auto EA = A->getLiteral(I); + auto EB = B->getLiteral(I); + if (EA < EB) + return true; + if (EA > EB) + return false; + } + return false; + }; + auto Res = Action(); + return Res; +} + +bool operator==(const SPIRVDecorateGeneric &A, const SPIRVDecorateGeneric &B) { + if (A.getTargetId() != B.getTargetId()) + return false; + if (A.getOpCode() != B.getOpCode()) + return false; + if (A.getDecorateKind() != B.getDecorateKind()) + return false; + if (A.getLiteralCount() != B.getLiteralCount()) + return false; + for (size_t I = 0, E = A.getLiteralCount(); I != E; ++I) { + auto EA = A.getLiteral(I); + auto EB = B.getLiteral(I); + if (EA != EB) + return false; + } + return true; +} +} + diff --git a/lib/SPIRV/libSPIRV/SPIRVDecorate.h b/lib/SPIRV/libSPIRV/SPIRVDecorate.h index 1683d45..eefdc1e 100644 --- a/lib/SPIRV/libSPIRV/SPIRVDecorate.h +++ b/lib/SPIRV/libSPIRV/SPIRVDecorate.h @@ -1,321 +1,321 @@ -//===- SPIRVDecorate.h - SPIR-V Decorations ----------------------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines SPIR-V decorations.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVDECORATE_HPP_
-#define SPIRVDECORATE_HPP_
-
-#include "SPIRVEntry.h"
-#include "SPIRVUtil.h"
-#include "SPIRVStream.h"
-#include <string>
-#include <vector>
-#include <utility>
-
-namespace SPIRV{
-class SPIRVDecorationGroup;
-class SPIRVDecorateGeneric:public SPIRVAnnotationGeneric{
-public:
- // Complete constructor for decorations without literals
- SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec,
- SPIRVEntry *TheTarget);
- // Complete constructor for decorations with one word literal
- SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec,
- SPIRVEntry *TheTarget, SPIRVWord V);
- // Incomplete constructor
- SPIRVDecorateGeneric(Op OC);
-
- SPIRVWord getLiteral(size_t) const;
- Decoration getDecorateKind() const;
- size_t getLiteralCount() const;
- /// Compare for kind and literal only.
- struct Comparator {
- bool operator ()(const SPIRVDecorateGeneric *A, const SPIRVDecorateGeneric *B) const;
- };
- /// Compare kind, literals and target.
- friend bool operator==(const SPIRVDecorateGeneric &A,
- const SPIRVDecorateGeneric &B);
-
- SPIRVDecorationGroup* getOwner() const {
- return Owner;
- }
-
- void setOwner(SPIRVDecorationGroup* owner) {
- Owner = owner;
- }
-
- SPIRVCapVec getRequiredCapability() const {
- return getCapability(Dec);
- }
-
- SPIRVWord getRequiredSPIRVVersion() const override {
- switch (Dec) {
- case DecorationSpecId:
- if (getModule()->hasCapability(CapabilityKernel))
- return SPIRV_1_1;
- else
- return SPIRV_1_0;
-
- case DecorationMaxByteOffset:
- return SPIRV_1_1;
-
- default:
- return SPIRV_1_0;
- }
- }
-
-protected:
- Decoration Dec;
- std::vector<SPIRVWord> Literals;
- SPIRVDecorationGroup *Owner; // Owning decorate group
-};
-
-class SPIRVDecorateSet: public std::multiset<SPIRVDecorateGeneric *,
- SPIRVDecorateGeneric::Comparator> {
- public:
- typedef std::multiset<SPIRVDecorateGeneric *,
- SPIRVDecorateGeneric::Comparator> BaseType;
- iterator insert(value_type& Dec) {
- auto ER = BaseType::equal_range(Dec);
- for (auto I = ER.first, E = ER.second; I != E; ++I) {
- SPIRVDBG(spvdbgs() << "[compare decorate] " << *Dec
- << " vs " << **I << " : ");
- if (**I == *Dec)
- return I;
- SPIRVDBG(spvdbgs() << " diff\n");
- }
- SPIRVDBG(spvdbgs() << "[add decorate] " << *Dec << '\n');
- return BaseType::insert(Dec);
- }
-};
-
-class SPIRVDecorate:public SPIRVDecorateGeneric{
-public:
- static const Op OC = OpDecorate;
- static const SPIRVWord FixedWC = 3;
- // Complete constructor for decorations without literals
- SPIRVDecorate(Decoration TheDec, SPIRVEntry *TheTarget)
- :SPIRVDecorateGeneric(OC, 3, TheDec, TheTarget){}
- // Complete constructor for decorations with one word literal
- SPIRVDecorate(Decoration TheDec, SPIRVEntry *TheTarget, SPIRVWord V)
- :SPIRVDecorateGeneric(OC, 4, TheDec, TheTarget, V){}
- // Incomplete constructor
- SPIRVDecorate():SPIRVDecorateGeneric(OC){}
-
- _SPIRV_DCL_ENCDEC
- void setWordCount(SPIRVWord);
- void validate()const {
- SPIRVDecorateGeneric::validate();
- assert(WordCount == Literals.size() + FixedWC);
- }
-
-};
-
-class SPIRVDecorateLinkageAttr:public SPIRVDecorate{
-public:
- // Complete constructor for LinkageAttributes decorations
- SPIRVDecorateLinkageAttr(SPIRVEntry *TheTarget,
- const std::string &Name, SPIRVLinkageTypeKind Kind)
- :SPIRVDecorate(DecorationLinkageAttributes, TheTarget) {
- for (auto &I:getVec(Name))
- Literals.push_back(I);
- Literals.push_back(Kind);
- WordCount += Literals.size();
- }
- // Incomplete constructor
- SPIRVDecorateLinkageAttr():SPIRVDecorate(){}
-
- std::string getLinkageName() const {
- return getString(Literals.cbegin(), Literals.cend() - 1);
- }
- SPIRVLinkageTypeKind getLinkageType() const {
- return (SPIRVLinkageTypeKind)Literals.back();
- }
-
- static void encodeLiterals(SPIRVEncoder& Encoder,
- const std::vector<SPIRVWord>& Literals) {
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
- if(SPIRVUseTextFormat) {
- Encoder << getString(Literals.cbegin(), Literals.cend() - 1);
- Encoder.OS << " ";
- Encoder << (SPIRVLinkageTypeKind)Literals.back();
- } else
-#endif
- Encoder << Literals;
- }
-
- static void decodeLiterals(SPIRVDecoder& Decoder, std::vector<SPIRVWord>& Literals) {
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
- if(SPIRVUseTextFormat) {
- std::string Name;
- Decoder >> Name;
- SPIRVLinkageTypeKind Kind;
- Decoder >> Kind;
- std::copy_n(getVec(Name).begin(), Literals.size()-1, Literals.begin());
- Literals.back() = Kind;
- } else
-#endif
- Decoder >> Literals;
- }
-};
-
-class SPIRVMemberDecorate:public SPIRVDecorateGeneric{
-public:
- static const Op OC = OpMemberDecorate;
- static const SPIRVWord FixedWC = 4;
- // Complete constructor for decorations without literals
- SPIRVMemberDecorate(Decoration TheDec, SPIRVWord Member,
- SPIRVEntry *TheTarget)
- :SPIRVDecorateGeneric(OC, 4, TheDec, TheTarget),
- MemberNumber(Member){}
-
- // Complete constructor for decorations with one word literal
- SPIRVMemberDecorate(Decoration TheDec, SPIRVWord Member,
- SPIRVEntry *TheTarget, SPIRVWord V)
- :SPIRVDecorateGeneric(OC, 5, TheDec, TheTarget, V),
- MemberNumber(Member){}
-
- // Incomplete constructor
- SPIRVMemberDecorate():SPIRVDecorateGeneric(OC), MemberNumber(SPIRVWORD_MAX){}
-
- SPIRVWord getMemberNumber() const { return MemberNumber;}
- std::pair<SPIRVWord, Decoration> getPair() const {
- return std::make_pair(MemberNumber, Dec);
- }
-
- _SPIRV_DCL_ENCDEC
- void setWordCount(SPIRVWord);
-
- void validate()const {
- SPIRVDecorateGeneric::validate();
- assert(WordCount == Literals.size() + FixedWC);
- }
-protected:
- SPIRVWord MemberNumber;
-};
-
-class SPIRVDecorationGroup:public SPIRVEntry{
-public:
- static const Op OC = OpDecorationGroup;
- static const SPIRVWord WC = 2;
- // Complete constructor. Does not populate Decorations.
- SPIRVDecorationGroup(SPIRVModule *TheModule, SPIRVId TheId)
- :SPIRVEntry(TheModule, WC, OC, TheId){
- validate();
- };
- // Incomplete constructor
- SPIRVDecorationGroup():SPIRVEntry(OC){}
- void encodeAll(spv_ostream &O) const;
- _SPIRV_DCL_ENCDEC
- // Move the given decorates to the decoration group
- void takeDecorates(SPIRVDecorateSet &Decs) {
- Decorations = std::move(Decs);
- for (auto &I:Decorations)
- const_cast<SPIRVDecorateGeneric *>(I)->setOwner(this);
- Decs.clear();
- }
-
- SPIRVDecorateSet& getDecorations() {
- return Decorations;
- }
-
-protected:
- SPIRVDecorateSet Decorations;
- void validate()const {
- assert(OpCode == OC);
- assert(WordCount == WC);
- }
-};
-
-class SPIRVGroupDecorateGeneric:public SPIRVEntryNoIdGeneric{
-public:
- static const SPIRVWord FixedWC = 2;
- // Complete constructor
- SPIRVGroupDecorateGeneric(Op OC, SPIRVDecorationGroup *TheGroup,
- const std::vector<SPIRVId> &TheTargets)
- :SPIRVEntryNoIdGeneric(TheGroup->getModule(), FixedWC + TheTargets.size(),
- OC),
- DecorationGroup(TheGroup), Targets(TheTargets){
- }
- // Incomplete constructor
- SPIRVGroupDecorateGeneric(Op OC)
- :SPIRVEntryNoIdGeneric(OC), DecorationGroup(nullptr){}
-
- void setWordCount(SPIRVWord WC) {
- SPIRVEntryNoIdGeneric::setWordCount(WC);
- Targets.resize(WC - FixedWC);
- }
- virtual void decorateTargets() = 0;
- _SPIRV_DCL_ENCDEC
-protected:
- SPIRVDecorationGroup *DecorationGroup;
- std::vector<SPIRVId> Targets;
-};
-
-class SPIRVGroupDecorate:public SPIRVGroupDecorateGeneric{
-public:
- static const Op OC = OpGroupDecorate;
- // Complete constructor
- SPIRVGroupDecorate(SPIRVDecorationGroup *TheGroup,
- const std::vector<SPIRVId> &TheTargets)
- :SPIRVGroupDecorateGeneric(OC, TheGroup, TheTargets){}
- // Incomplete constructor
- SPIRVGroupDecorate()
- :SPIRVGroupDecorateGeneric(OC){}
-
- virtual void decorateTargets();
-};
-
-class SPIRVGroupMemberDecorate:public SPIRVGroupDecorateGeneric{
-public:
- static const Op OC = OpGroupMemberDecorate;
- // Complete constructor
- SPIRVGroupMemberDecorate(SPIRVDecorationGroup *TheGroup,
- const std::vector<SPIRVId> &TheTargets)
- :SPIRVGroupDecorateGeneric(OC, TheGroup, TheTargets){}
- // Incomplete constructor
- SPIRVGroupMemberDecorate()
- :SPIRVGroupDecorateGeneric(OC){}
-
- virtual void decorateTargets();
-};
-
-}
-
-
-#endif /* SPIRVDECORATE_HPP_ */
+//===- SPIRVDecorate.h - SPIR-V Decorations ----------------------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines SPIR-V decorations. +/// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVDECORATE_HPP_ +#define SPIRVDECORATE_HPP_ + +#include "SPIRVEntry.h" +#include "SPIRVUtil.h" +#include "SPIRVStream.h" +#include <string> +#include <vector> +#include <utility> + +namespace SPIRV{ +class SPIRVDecorationGroup; +class SPIRVDecorateGeneric:public SPIRVAnnotationGeneric{ +public: + // Complete constructor for decorations without literals + SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec, + SPIRVEntry *TheTarget); + // Complete constructor for decorations with one word literal + SPIRVDecorateGeneric(Op OC, SPIRVWord WC, Decoration TheDec, + SPIRVEntry *TheTarget, SPIRVWord V); + // Incomplete constructor + SPIRVDecorateGeneric(Op OC); + + SPIRVWord getLiteral(size_t) const; + Decoration getDecorateKind() const; + size_t getLiteralCount() const; + /// Compare for kind and literal only. + struct Comparator { + bool operator ()(const SPIRVDecorateGeneric *A, const SPIRVDecorateGeneric *B) const; + }; + /// Compare kind, literals and target. + friend bool operator==(const SPIRVDecorateGeneric &A, + const SPIRVDecorateGeneric &B); + + SPIRVDecorationGroup* getOwner() const { + return Owner; + } + + void setOwner(SPIRVDecorationGroup* owner) { + Owner = owner; + } + + SPIRVCapVec getRequiredCapability() const { + return getCapability(Dec); + } + + SPIRVWord getRequiredSPIRVVersion() const override { + switch (Dec) { + case DecorationSpecId: + if (getModule()->hasCapability(CapabilityKernel)) + return SPIRV_1_1; + else + return SPIRV_1_0; + + case DecorationMaxByteOffset: + return SPIRV_1_1; + + default: + return SPIRV_1_0; + } + } + +protected: + Decoration Dec; + std::vector<SPIRVWord> Literals; + SPIRVDecorationGroup *Owner; // Owning decorate group +}; + +class SPIRVDecorateSet: public std::multiset<SPIRVDecorateGeneric *, + SPIRVDecorateGeneric::Comparator> { + public: + typedef std::multiset<SPIRVDecorateGeneric *, + SPIRVDecorateGeneric::Comparator> BaseType; + iterator insert(value_type& Dec) { + auto ER = BaseType::equal_range(Dec); + for (auto I = ER.first, E = ER.second; I != E; ++I) { + SPIRVDBG(spvdbgs() << "[compare decorate] " << *Dec + << " vs " << **I << " : "); + if (**I == *Dec) + return I; + SPIRVDBG(spvdbgs() << " diff\n"); + } + SPIRVDBG(spvdbgs() << "[add decorate] " << *Dec << '\n'); + return BaseType::insert(Dec); + } +}; + +class SPIRVDecorate:public SPIRVDecorateGeneric{ +public: + static const Op OC = OpDecorate; + static const SPIRVWord FixedWC = 3; + // Complete constructor for decorations without literals + SPIRVDecorate(Decoration TheDec, SPIRVEntry *TheTarget) + :SPIRVDecorateGeneric(OC, 3, TheDec, TheTarget){} + // Complete constructor for decorations with one word literal + SPIRVDecorate(Decoration TheDec, SPIRVEntry *TheTarget, SPIRVWord V) + :SPIRVDecorateGeneric(OC, 4, TheDec, TheTarget, V){} + // Incomplete constructor + SPIRVDecorate():SPIRVDecorateGeneric(OC){} + + _SPIRV_DCL_ENCDEC + void setWordCount(SPIRVWord); + void validate()const { + SPIRVDecorateGeneric::validate(); + assert(WordCount == Literals.size() + FixedWC); + } + +}; + +class SPIRVDecorateLinkageAttr:public SPIRVDecorate{ +public: + // Complete constructor for LinkageAttributes decorations + SPIRVDecorateLinkageAttr(SPIRVEntry *TheTarget, + const std::string &Name, SPIRVLinkageTypeKind Kind) + :SPIRVDecorate(DecorationLinkageAttributes, TheTarget) { + for (auto &I:getVec(Name)) + Literals.push_back(I); + Literals.push_back(Kind); + WordCount += Literals.size(); + } + // Incomplete constructor + SPIRVDecorateLinkageAttr():SPIRVDecorate(){} + + std::string getLinkageName() const { + return getString(Literals.cbegin(), Literals.cend() - 1); + } + SPIRVLinkageTypeKind getLinkageType() const { + return (SPIRVLinkageTypeKind)Literals.back(); + } + + static void encodeLiterals(SPIRVEncoder& Encoder, + const std::vector<SPIRVWord>& Literals) { +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if(SPIRVUseTextFormat) { + Encoder << getString(Literals.cbegin(), Literals.cend() - 1); + Encoder.OS << " "; + Encoder << (SPIRVLinkageTypeKind)Literals.back(); + } else +#endif + Encoder << Literals; + } + + static void decodeLiterals(SPIRVDecoder& Decoder, std::vector<SPIRVWord>& Literals) { +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if(SPIRVUseTextFormat) { + std::string Name; + Decoder >> Name; + SPIRVLinkageTypeKind Kind; + Decoder >> Kind; + std::copy_n(getVec(Name).begin(), Literals.size()-1, Literals.begin()); + Literals.back() = Kind; + } else +#endif + Decoder >> Literals; + } +}; + +class SPIRVMemberDecorate:public SPIRVDecorateGeneric{ +public: + static const Op OC = OpMemberDecorate; + static const SPIRVWord FixedWC = 4; + // Complete constructor for decorations without literals + SPIRVMemberDecorate(Decoration TheDec, SPIRVWord Member, + SPIRVEntry *TheTarget) + :SPIRVDecorateGeneric(OC, 4, TheDec, TheTarget), + MemberNumber(Member){} + + // Complete constructor for decorations with one word literal + SPIRVMemberDecorate(Decoration TheDec, SPIRVWord Member, + SPIRVEntry *TheTarget, SPIRVWord V) + :SPIRVDecorateGeneric(OC, 5, TheDec, TheTarget, V), + MemberNumber(Member){} + + // Incomplete constructor + SPIRVMemberDecorate():SPIRVDecorateGeneric(OC), MemberNumber(SPIRVWORD_MAX){} + + SPIRVWord getMemberNumber() const { return MemberNumber;} + std::pair<SPIRVWord, Decoration> getPair() const { + return std::make_pair(MemberNumber, Dec); + } + + _SPIRV_DCL_ENCDEC + void setWordCount(SPIRVWord); + + void validate()const { + SPIRVDecorateGeneric::validate(); + assert(WordCount == Literals.size() + FixedWC); + } +protected: + SPIRVWord MemberNumber; +}; + +class SPIRVDecorationGroup:public SPIRVEntry{ +public: + static const Op OC = OpDecorationGroup; + static const SPIRVWord WC = 2; + // Complete constructor. Does not populate Decorations. + SPIRVDecorationGroup(SPIRVModule *TheModule, SPIRVId TheId) + :SPIRVEntry(TheModule, WC, OC, TheId){ + validate(); + }; + // Incomplete constructor + SPIRVDecorationGroup():SPIRVEntry(OC){} + void encodeAll(spv_ostream &O) const; + _SPIRV_DCL_ENCDEC + // Move the given decorates to the decoration group + void takeDecorates(SPIRVDecorateSet &Decs) { + Decorations = std::move(Decs); + for (auto &I:Decorations) + const_cast<SPIRVDecorateGeneric *>(I)->setOwner(this); + Decs.clear(); + } + + SPIRVDecorateSet& getDecorations() { + return Decorations; + } + +protected: + SPIRVDecorateSet Decorations; + void validate()const { + assert(OpCode == OC); + assert(WordCount == WC); + } +}; + +class SPIRVGroupDecorateGeneric:public SPIRVEntryNoIdGeneric{ +public: + static const SPIRVWord FixedWC = 2; + // Complete constructor + SPIRVGroupDecorateGeneric(Op OC, SPIRVDecorationGroup *TheGroup, + const std::vector<SPIRVId> &TheTargets) + :SPIRVEntryNoIdGeneric(TheGroup->getModule(), FixedWC + TheTargets.size(), + OC), + DecorationGroup(TheGroup), Targets(TheTargets){ + } + // Incomplete constructor + SPIRVGroupDecorateGeneric(Op OC) + :SPIRVEntryNoIdGeneric(OC), DecorationGroup(nullptr){} + + void setWordCount(SPIRVWord WC) { + SPIRVEntryNoIdGeneric::setWordCount(WC); + Targets.resize(WC - FixedWC); + } + virtual void decorateTargets() = 0; + _SPIRV_DCL_ENCDEC +protected: + SPIRVDecorationGroup *DecorationGroup; + std::vector<SPIRVId> Targets; +}; + +class SPIRVGroupDecorate:public SPIRVGroupDecorateGeneric{ +public: + static const Op OC = OpGroupDecorate; + // Complete constructor + SPIRVGroupDecorate(SPIRVDecorationGroup *TheGroup, + const std::vector<SPIRVId> &TheTargets) + :SPIRVGroupDecorateGeneric(OC, TheGroup, TheTargets){} + // Incomplete constructor + SPIRVGroupDecorate() + :SPIRVGroupDecorateGeneric(OC){} + + virtual void decorateTargets(); +}; + +class SPIRVGroupMemberDecorate:public SPIRVGroupDecorateGeneric{ +public: + static const Op OC = OpGroupMemberDecorate; + // Complete constructor + SPIRVGroupMemberDecorate(SPIRVDecorationGroup *TheGroup, + const std::vector<SPIRVId> &TheTargets) + :SPIRVGroupDecorateGeneric(OC, TheGroup, TheTargets){} + // Incomplete constructor + SPIRVGroupMemberDecorate() + :SPIRVGroupDecorateGeneric(OC){} + + virtual void decorateTargets(); +}; + +} + + +#endif /* SPIRVDECORATE_HPP_ */ diff --git a/lib/SPIRV/libSPIRV/SPIRVEntry.cpp b/lib/SPIRV/libSPIRV/SPIRVEntry.cpp index 3bd8818..d350536 100644 --- a/lib/SPIRV/libSPIRV/SPIRVEntry.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVEntry.cpp @@ -1,652 +1,652 @@ -//===- SPIRVEntry.cpp - Base Class for SPIR-V Entities -----------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file implements base class for SPIR-V entities.
-///
-//===----------------------------------------------------------------------===//
-
-#include "SPIRVEntry.h"
-#include "SPIRVDebug.h"
-#include "SPIRVType.h"
-#include "SPIRVFunction.h"
-#include "SPIRVBasicBlock.h"
-#include "SPIRVInstruction.h"
-#include "SPIRVDecorate.h"
-#include "SPIRVStream.h"
-
-#include <algorithm>
-#include <map>
-#include <set>
-#include <sstream>
-#include <string>
-#include <utility>
-
-using namespace SPIRV;
-
-namespace SPIRV{
-
-template<typename T>
-SPIRVEntry* create() {
- return new T();
-}
-
-SPIRVEntry *
-SPIRVEntry::create(Op OpCode) {
- typedef SPIRVEntry *(*SPIRVFactoryTy)();
- struct TableEntry {
- Op Opn;
- SPIRVFactoryTy Factory;
- operator std::pair<const Op, SPIRVFactoryTy>() {
- return std::make_pair(Opn, Factory);
- }
- };
-
- static TableEntry Table[] = {
-#define _SPIRV_OP(x,...) {Op##x, &SPIRV::create<SPIRV##x>},
-#include "SPIRVOpCodeEnum.h"
-#undef _SPIRV_OP
- };
-
- typedef std::map<Op, SPIRVFactoryTy> OpToFactoryMapTy;
- static const OpToFactoryMapTy OpToFactoryMap(std::begin(Table),
- std::end(Table));
-
- OpToFactoryMapTy::const_iterator Loc = OpToFactoryMap.find(OpCode);
- if (Loc != OpToFactoryMap.end())
- return Loc->second();
-
- SPIRVDBG(spvdbgs() << "No factory for OpCode " << (unsigned)OpCode << '\n';)
- assert (0 && "Not implemented");
- return 0;
-}
-
-std::unique_ptr<SPIRV::SPIRVEntry>
-SPIRVEntry::create_unique(Op OC) {
- return std::unique_ptr<SPIRVEntry>(create(OC));
-}
-
-std::unique_ptr<SPIRV::SPIRVExtInst>
-SPIRVEntry::create_unique(SPIRVExtInstSetKind Set,
- unsigned ExtOp) {
- return std::unique_ptr<SPIRVExtInst>(new SPIRVExtInst(Set, ExtOp));
-}
-
-SPIRVErrorLog &
-SPIRVEntry::getErrorLog()const {
- return Module->getErrorLog();
-}
-
-bool
-SPIRVEntry::exist(SPIRVId TheId)const {
- return Module->exist(TheId);
-}
-
-SPIRVEntry *
-SPIRVEntry::getOrCreate(SPIRVId TheId)const {
- SPIRVEntry *Entry = nullptr;
- bool Found = Module->exist(TheId, &Entry);
- if (!Found)
- return Module->addForward(TheId, nullptr);
- return Entry;
-}
-
-SPIRVValue *
-SPIRVEntry::getValue(SPIRVId TheId)const {
- return get<SPIRVValue>(TheId);
-}
-
-SPIRVType *
-SPIRVEntry::getValueType(SPIRVId TheId)const {
- return get<SPIRVValue>(TheId)->getType();
-}
-
-SPIRVEncoder
-SPIRVEntry::getEncoder(spv_ostream &O)const{
- return SPIRVEncoder(O);
-}
-
-SPIRVDecoder
-SPIRVEntry::getDecoder(std::istream& I){
- return SPIRVDecoder(I, *Module);
-}
-
-void
-SPIRVEntry::setWordCount(SPIRVWord TheWordCount){
- WordCount = TheWordCount;
-}
-
-void
-SPIRVEntry::setName(const std::string& TheName) {
- Name = TheName;
- SPIRVDBG(spvdbgs() << "Set name for obj " << Id << " " <<
- Name << '\n');
-}
-
-void
-SPIRVEntry::setModule(SPIRVModule *TheModule) {
- assert(TheModule && "Invalid module");
- if (TheModule == Module)
- return;
- assert(Module == NULL && "Cannot change owner of entry");
- Module = TheModule;
-}
-
-void
-SPIRVEntry::encode(spv_ostream &O) const {
- assert (0 && "Not implemented");
-}
-
-void
-SPIRVEntry::encodeName(spv_ostream &O) const {
- if (!Name.empty())
- O << SPIRVName(this, Name);
-}
-
-bool SPIRVEntry::isEndOfBlock() const {
- switch (OpCode) {
- case OpBranch:
- case OpBranchConditional:
- case OpSwitch:
- case OpKill:
- case OpReturn:
- case OpReturnValue:
- case OpUnreachable:
- return true;
- default:
- return false;
- }
-}
-
-void
-SPIRVEntry::encodeLine(spv_ostream &O) const {
- if (!Module)
- return;
- const std::shared_ptr<const SPIRVLine> &CurrLine = Module->getCurrentLine();
- if (Line && ((CurrLine && *Line != *CurrLine) || !CurrLine)) {
- O << *Line;
- Module->setCurrentLine(Line);
- }
- if (isEndOfBlock() || OpCode == OpNoLine)
- Module->setCurrentLine(nullptr);
-}
-
-void
-SPIRVEntry::encodeAll(spv_ostream &O) const {
- encodeLine(O);
- encodeWordCountOpCode(O);
- encode(O);
- encodeChildren(O);
-}
-
-void
-SPIRVEntry::encodeChildren(spv_ostream &O)const {
-}
-
-void
-SPIRVEntry::encodeWordCountOpCode(spv_ostream &O) const {
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
- if (SPIRVUseTextFormat) {
- getEncoder(O) << WordCount << OpCode;
- return;
- }
-#endif
- getEncoder(O) << mkWord(WordCount, OpCode);
-}
-// Read words from SPIRV binary and create members for SPIRVEntry.
-// The word count and op code has already been read before calling this
-// function for creating the SPIRVEntry. Therefore the input stream only
-// contains the remaining part of the words for the SPIRVEntry.
-void
-SPIRVEntry::decode(std::istream &I) {
- assert (0 && "Not implemented");
-}
-
-std::vector<SPIRVValue *>
-SPIRVEntry::getValues(const std::vector<SPIRVId>& IdVec)const {
- std::vector<SPIRVValue *> ValueVec;
- for (auto i:IdVec)
- ValueVec.push_back(getValue(i));
- return ValueVec;
-}
-
-std::vector<SPIRVType *>
-SPIRVEntry::getValueTypes(const std::vector<SPIRVId>& IdVec)const {
- std::vector<SPIRVType *> TypeVec;
- for (auto i:IdVec)
- TypeVec.push_back(getValue(i)->getType());
- return TypeVec;
-}
-
-std::vector<SPIRVId>
-SPIRVEntry::getIds(const std::vector<SPIRVValue *> ValueVec)const {
- std::vector<SPIRVId> IdVec;
- for (auto i:ValueVec)
- IdVec.push_back(i->getId());
- return IdVec;
-}
-
-SPIRVEntry *
-SPIRVEntry::getEntry(SPIRVId TheId) const {
- return Module->getEntry(TheId);
-}
-
-void
-SPIRVEntry::validateFunctionControlMask(SPIRVWord TheFCtlMask)
- const {
- SPIRVCK(isValidFunctionControlMask(TheFCtlMask),
- InvalidFunctionControlMask, "");
-}
-
-void
-SPIRVEntry::validateValues(const std::vector<SPIRVId> &Ids)const {
- for (auto I:Ids)
- getValue(I)->validate();
-}
-
-void
-SPIRVEntry::validateBuiltin(SPIRVWord TheSet, SPIRVWord Index)const {
- assert(TheSet != SPIRVWORD_MAX && Index != SPIRVWORD_MAX &&
- "Invalid builtin");
-}
-
-void
-SPIRVEntry::addDecorate(SPIRVDecorate *Dec) {
- auto Kind = Dec->getDecorateKind();
- Decorates.insert(std::make_pair(Dec->getDecorateKind(), Dec));
- Module->addDecorate(Dec);
- if (Kind == spv::DecorationLinkageAttributes) {
- auto *LinkageAttr = static_cast<const SPIRVDecorateLinkageAttr*>(Dec);
- setName(LinkageAttr->getLinkageName());
- }
- SPIRVDBG(spvdbgs() << "[addDecorate] " << *Dec << '\n';)
-}
-
-void
-SPIRVEntry::addDecorate(Decoration Kind) {
- addDecorate(new SPIRVDecorate(Kind, this));
-}
-
-void
-SPIRVEntry::addDecorate(Decoration Kind, SPIRVWord Literal) {
- addDecorate(new SPIRVDecorate(Kind, this, Literal));
-}
-
-void
-SPIRVEntry::eraseDecorate(Decoration Dec){
- Decorates.erase(Dec);
-}
-
-void
-SPIRVEntry::takeDecorates(SPIRVEntry *E){
- Decorates = std::move(E->Decorates);
- SPIRVDBG(spvdbgs() << "[takeDecorates] " << Id << '\n';)
-}
-
-void
-SPIRVEntry::setLine(const std::shared_ptr<const SPIRVLine>& L){
- Line = L;
- SPIRVDBG(spvdbgs() << "[setLine] " << *L << '\n';)
-}
-
-void
-SPIRVEntry::addMemberDecorate(SPIRVMemberDecorate *Dec){
- assert(canHaveMemberDecorates() && MemberDecorates.find(Dec->getPair()) ==
- MemberDecorates.end());
- MemberDecorates[Dec->getPair()] = Dec;
- Module->addDecorate(Dec);
- SPIRVDBG(spvdbgs() << "[addMemberDecorate] " << *Dec << '\n';)
-}
-
-void
-SPIRVEntry::addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind) {
- addMemberDecorate(new SPIRVMemberDecorate(Kind, MemberNumber, this));
-}
-
-void
-SPIRVEntry::addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind,
- SPIRVWord Literal) {
- addMemberDecorate(new SPIRVMemberDecorate(Kind, MemberNumber, this, Literal));
-}
-
-void
-SPIRVEntry::eraseMemberDecorate(SPIRVWord MemberNumber, Decoration Dec){
- MemberDecorates.erase(std::make_pair(MemberNumber, Dec));
-}
-
-void
-SPIRVEntry::takeMemberDecorates(SPIRVEntry *E){
- MemberDecorates = std::move(E->MemberDecorates);
- SPIRVDBG(spvdbgs() << "[takeMemberDecorates] " << Id << '\n';)
-}
-
-void
-SPIRVEntry::takeAnnotations(SPIRVForward *E){
- Module->setName(this, E->getName());
- takeDecorates(E);
- takeMemberDecorates(E);
- if (OpCode == OpFunction)
- static_cast<SPIRVFunction *>(this)->takeExecutionModes(E);
-}
-
-// Check if an entry has Kind of decoration and get the literal of the
-// first decoration of such kind at Index.
-bool
-SPIRVEntry::hasDecorate(Decoration Kind, size_t Index, SPIRVWord *Result)const {
- DecorateMapType::const_iterator Loc = Decorates.find(Kind);
- if (Loc == Decorates.end())
- return false;
- if (Result)
- *Result = Loc->second->getLiteral(Index);
- return true;
-}
-
-// Get literals of all decorations of Kind at Index.
-std::set<SPIRVWord>
-SPIRVEntry::getDecorate(Decoration Kind, size_t Index) const {
- auto Range = Decorates.equal_range(Kind);
- std::set<SPIRVWord> Value;
- for (auto I = Range.first, E = Range.second; I != E; ++I) {
- assert(Index < I->second->getLiteralCount() && "Invalid index");
- Value.insert(I->second->getLiteral(Index));
- }
- return Value;
-}
-
-bool
-SPIRVEntry::hasLinkageType() const {
- return OpCode == OpFunction || OpCode == OpVariable;
-}
-
-void
-SPIRVEntry::encodeDecorate(spv_ostream &O) const {
- for (auto& i:Decorates)
- O << *i.second;
-}
-
-SPIRVLinkageTypeKind
-SPIRVEntry::getLinkageType() const {
- assert(hasLinkageType());
- DecorateMapType::const_iterator Loc = Decorates.find(DecorationLinkageAttributes);
- if (Loc == Decorates.end())
- return LinkageTypeInternal;
- return static_cast<const SPIRVDecorateLinkageAttr*>(Loc->second)->getLinkageType();
-}
-
-void
-SPIRVEntry::setLinkageType(SPIRVLinkageTypeKind LT) {
- assert(isValid(LT));
- assert(hasLinkageType());
- addDecorate(new SPIRVDecorateLinkageAttr(this, Name, LT));
-}
-
-void
-SPIRVEntry::updateModuleVersion() const {
- if (!Module)
- return;
-
- Module->setMinSPIRVVersion(getRequiredSPIRVVersion());
-}
-
-spv_ostream &
-operator<<(spv_ostream &O, const SPIRVEntry &E) {
- E.validate();
- E.encodeAll(O);
- O << SPIRVNL();
- return O;
-}
-
-std::istream &
-operator>>(std::istream &I, SPIRVEntry &E) {
- E.decode(I);
- return I;
-}
-
-SPIRVEntryPoint::SPIRVEntryPoint(SPIRVModule *TheModule,
- SPIRVExecutionModelKind TheExecModel, SPIRVId TheId,
- const std::string &TheName)
- :SPIRVAnnotation(TheModule->get<SPIRVFunction>(TheId),
- getSizeInWords(TheName) + 3), ExecModel(TheExecModel), Name(TheName){
-}
-
-void
-SPIRVEntryPoint::encode(spv_ostream &O) const {
- getEncoder(O) << ExecModel << Target << Name;
-}
-
-void
-SPIRVEntryPoint::decode(std::istream &I) {
- getDecoder(I) >> ExecModel >> Target >> Name;
- Module->setName(getOrCreateTarget(), Name);
- Module->addEntryPoint(ExecModel, Target);
-}
-
-void
-SPIRVExecutionMode::encode(spv_ostream &O) const {
- getEncoder(O) << Target << ExecMode << WordLiterals;
-}
-
-void
-SPIRVExecutionMode::decode(std::istream &I) {
- getDecoder(I) >> Target >> ExecMode;
- switch(ExecMode) {
- case ExecutionModeLocalSize:
- case ExecutionModeLocalSizeHint:
- WordLiterals.resize(3);
- break;
- case ExecutionModeInvocations:
- case ExecutionModeOutputVertices:
- case ExecutionModeVecTypeHint:
- WordLiterals.resize(1);
- break;
- default:
- // Do nothing. Keep this to avoid VS2013 warning.
- break;
- }
- getDecoder(I) >> WordLiterals;
- getOrCreateTarget()->addExecutionMode(this);
-}
-
-SPIRVForward *
-SPIRVAnnotationGeneric::getOrCreateTarget()const {
- SPIRVEntry *Entry = nullptr;
- bool Found = Module->exist(Target, &Entry);
- assert((!Found || Entry->getOpCode() == OpForward) &&
- "Annotations only allowed on forward");
- if (!Found)
- Entry = Module->addForward(Target, nullptr);
- return static_cast<SPIRVForward *>(Entry);
-}
-
-SPIRVName::SPIRVName(const SPIRVEntry *TheTarget, const std::string& TheStr)
- :SPIRVAnnotation(TheTarget, getSizeInWords(TheStr) + 2), Str(TheStr){
-}
-
-void
-SPIRVName::encode(spv_ostream &O) const {
- getEncoder(O) << Target << Str;
-}
-
-void
-SPIRVName::decode(std::istream &I) {
- getDecoder(I) >> Target >> Str;
- Module->setName(getOrCreateTarget(), Str);
-}
-
-void
-SPIRVName::validate() const {
- assert(WordCount == getSizeInWords(Str) + 2 && "Incorrect word count");
-}
-
-_SPIRV_IMP_ENCDEC2(SPIRVString, Id, Str)
-_SPIRV_IMP_ENCDEC3(SPIRVMemberName, Target, MemberNumber, Str)
-
-void
-SPIRVLine::encode(spv_ostream &O) const {
- getEncoder(O) << FileName << Line << Column;
-}
-
-void
-SPIRVLine::decode(std::istream &I) {
- getDecoder(I) >> FileName >> Line >> Column;
- std::shared_ptr<const SPIRVLine> L(this);
- Module->setCurrentLine(L);
-}
-
-void
-SPIRVLine::validate() const {
- assert(OpCode == OpLine);
- assert(WordCount == 4);
- assert(get<SPIRVEntry>(FileName)->getOpCode() == OpString);
- assert(Line != SPIRVWORD_MAX);
- assert(Column != SPIRVWORD_MAX);
- assert(!hasId());
-}
-
-void
-SPIRVMemberName::validate() const {
- assert(OpCode == OpMemberName);
- assert(WordCount == getSizeInWords(Str) + FixedWC);
- assert(get<SPIRVEntry>(Target)->getOpCode() == OpTypeStruct);
- assert(MemberNumber < get<SPIRVTypeStruct>(Target)->getStructMemberCount());
-}
-
-SPIRVExtInstImport::SPIRVExtInstImport(SPIRVModule *TheModule, SPIRVId TheId,
- const std::string &TheStr):
- SPIRVEntry(TheModule, 2 + getSizeInWords(TheStr), OC, TheId), Str(TheStr){
- validate();
-}
-
-void
-SPIRVExtInstImport::encode(spv_ostream &O) const {
- getEncoder(O) << Id << Str;
-}
-
-void
-SPIRVExtInstImport::decode(std::istream &I) {
- getDecoder(I) >> Id >> Str;
- Module->importBuiltinSetWithId(Str, Id);
-}
-
-void
-SPIRVExtInstImport::validate() const {
- SPIRVEntry::validate();
- assert(!Str.empty() && "Invalid builtin set");
-}
-
-void
-SPIRVMemoryModel::encode(spv_ostream &O) const {
- getEncoder(O) << Module->getAddressingModel() <<
- Module->getMemoryModel();
-}
-
-void
-SPIRVMemoryModel::decode(std::istream &I) {
- SPIRVAddressingModelKind AddrModel;
- SPIRVMemoryModelKind MemModel;
- getDecoder(I) >> AddrModel >> MemModel;
- Module->setAddressingModel(AddrModel);
- Module->setMemoryModel(MemModel);
-}
-
-void
-SPIRVMemoryModel::validate() const {
- auto AM = Module->getAddressingModel();
- auto MM = Module->getMemoryModel();
- SPIRVCK(isValid(AM), InvalidAddressingModel, "Actual is "+AM );
- SPIRVCK(isValid(MM), InvalidMemoryModel, "Actual is "+MM);
-}
-
-void
-SPIRVSource::encode(spv_ostream &O) const {
- SPIRVWord Ver = SPIRVWORD_MAX;
- auto Language = Module->getSourceLanguage(&Ver);
- getEncoder(O) << Language << Ver;
-}
-
-void
-SPIRVSource::decode(std::istream &I) {
- SourceLanguage Lang = SourceLanguageUnknown;
- SPIRVWord Ver = SPIRVWORD_MAX;
- getDecoder(I) >> Lang >> Ver;
- Module->setSourceLanguage(Lang, Ver);
-}
-
-SPIRVSourceExtension::SPIRVSourceExtension(SPIRVModule *M,
- const std::string &SS)
- :SPIRVEntryNoId(M, 1 + getSizeInWords(SS)), S(SS){}
-
-void
-SPIRVSourceExtension::encode(spv_ostream &O) const {
- getEncoder(O) << S;
-}
-
-void
-SPIRVSourceExtension::decode(std::istream &I) {
- getDecoder(I) >> S;
- Module->getSourceExtension().insert(S);
-}
-
-SPIRVExtension::SPIRVExtension(SPIRVModule *M, const std::string &SS)
- :SPIRVEntryNoId(M, 1 + getSizeInWords(SS)), S(SS){}
-
-void
-SPIRVExtension::encode(spv_ostream &O) const {
- getEncoder(O) << S;
-}
-
-void
-SPIRVExtension::decode(std::istream &I) {
- getDecoder(I) >> S;
- Module->getExtension().insert(S);
-}
-
-SPIRVCapability::SPIRVCapability(SPIRVModule *M, SPIRVCapabilityKind K)
- :SPIRVEntryNoId(M, 2), Kind(K){
- updateModuleVersion();
-}
-
-void
-SPIRVCapability::encode(spv_ostream &O) const {
- getEncoder(O) << Kind;
-}
-
-void
-SPIRVCapability::decode(std::istream &I) {
- getDecoder(I) >> Kind;
- Module->addCapability(Kind);
-}
-
-} // namespace SPIRV
-
+//===- SPIRVEntry.cpp - Base Class for SPIR-V Entities -----------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file implements base class for SPIR-V entities. +/// +//===----------------------------------------------------------------------===// + +#include "SPIRVEntry.h" +#include "SPIRVDebug.h" +#include "SPIRVType.h" +#include "SPIRVFunction.h" +#include "SPIRVBasicBlock.h" +#include "SPIRVInstruction.h" +#include "SPIRVDecorate.h" +#include "SPIRVStream.h" + +#include <algorithm> +#include <map> +#include <set> +#include <sstream> +#include <string> +#include <utility> + +using namespace SPIRV; + +namespace SPIRV{ + +template<typename T> +SPIRVEntry* create() { + return new T(); +} + +SPIRVEntry * +SPIRVEntry::create(Op OpCode) { + typedef SPIRVEntry *(*SPIRVFactoryTy)(); + struct TableEntry { + Op Opn; + SPIRVFactoryTy Factory; + operator std::pair<const Op, SPIRVFactoryTy>() { + return std::make_pair(Opn, Factory); + } + }; + + static TableEntry Table[] = { +#define _SPIRV_OP(x,...) {Op##x, &SPIRV::create<SPIRV##x>}, +#include "SPIRVOpCodeEnum.h" +#undef _SPIRV_OP + }; + + typedef std::map<Op, SPIRVFactoryTy> OpToFactoryMapTy; + static const OpToFactoryMapTy OpToFactoryMap(std::begin(Table), + std::end(Table)); + + OpToFactoryMapTy::const_iterator Loc = OpToFactoryMap.find(OpCode); + if (Loc != OpToFactoryMap.end()) + return Loc->second(); + + SPIRVDBG(spvdbgs() << "No factory for OpCode " << (unsigned)OpCode << '\n';) + assert (0 && "Not implemented"); + return 0; +} + +std::unique_ptr<SPIRV::SPIRVEntry> +SPIRVEntry::create_unique(Op OC) { + return std::unique_ptr<SPIRVEntry>(create(OC)); +} + +std::unique_ptr<SPIRV::SPIRVExtInst> +SPIRVEntry::create_unique(SPIRVExtInstSetKind Set, + unsigned ExtOp) { + return std::unique_ptr<SPIRVExtInst>(new SPIRVExtInst(Set, ExtOp)); +} + +SPIRVErrorLog & +SPIRVEntry::getErrorLog()const { + return Module->getErrorLog(); +} + +bool +SPIRVEntry::exist(SPIRVId TheId)const { + return Module->exist(TheId); +} + +SPIRVEntry * +SPIRVEntry::getOrCreate(SPIRVId TheId)const { + SPIRVEntry *Entry = nullptr; + bool Found = Module->exist(TheId, &Entry); + if (!Found) + return Module->addForward(TheId, nullptr); + return Entry; +} + +SPIRVValue * +SPIRVEntry::getValue(SPIRVId TheId)const { + return get<SPIRVValue>(TheId); +} + +SPIRVType * +SPIRVEntry::getValueType(SPIRVId TheId)const { + return get<SPIRVValue>(TheId)->getType(); +} + +SPIRVEncoder +SPIRVEntry::getEncoder(spv_ostream &O)const{ + return SPIRVEncoder(O); +} + +SPIRVDecoder +SPIRVEntry::getDecoder(std::istream& I){ + return SPIRVDecoder(I, *Module); +} + +void +SPIRVEntry::setWordCount(SPIRVWord TheWordCount){ + WordCount = TheWordCount; +} + +void +SPIRVEntry::setName(const std::string& TheName) { + Name = TheName; + SPIRVDBG(spvdbgs() << "Set name for obj " << Id << " " << + Name << '\n'); +} + +void +SPIRVEntry::setModule(SPIRVModule *TheModule) { + assert(TheModule && "Invalid module"); + if (TheModule == Module) + return; + assert(Module == NULL && "Cannot change owner of entry"); + Module = TheModule; +} + +void +SPIRVEntry::encode(spv_ostream &O) const { + assert (0 && "Not implemented"); +} + +void +SPIRVEntry::encodeName(spv_ostream &O) const { + if (!Name.empty()) + O << SPIRVName(this, Name); +} + +bool SPIRVEntry::isEndOfBlock() const { + switch (OpCode) { + case OpBranch: + case OpBranchConditional: + case OpSwitch: + case OpKill: + case OpReturn: + case OpReturnValue: + case OpUnreachable: + return true; + default: + return false; + } +} + +void +SPIRVEntry::encodeLine(spv_ostream &O) const { + if (!Module) + return; + const std::shared_ptr<const SPIRVLine> &CurrLine = Module->getCurrentLine(); + if (Line && ((CurrLine && *Line != *CurrLine) || !CurrLine)) { + O << *Line; + Module->setCurrentLine(Line); + } + if (isEndOfBlock() || OpCode == OpNoLine) + Module->setCurrentLine(nullptr); +} + +void +SPIRVEntry::encodeAll(spv_ostream &O) const { + encodeLine(O); + encodeWordCountOpCode(O); + encode(O); + encodeChildren(O); +} + +void +SPIRVEntry::encodeChildren(spv_ostream &O)const { +} + +void +SPIRVEntry::encodeWordCountOpCode(spv_ostream &O) const { +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if (SPIRVUseTextFormat) { + getEncoder(O) << WordCount << OpCode; + return; + } +#endif + getEncoder(O) << mkWord(WordCount, OpCode); +} +// Read words from SPIRV binary and create members for SPIRVEntry. +// The word count and op code has already been read before calling this +// function for creating the SPIRVEntry. Therefore the input stream only +// contains the remaining part of the words for the SPIRVEntry. +void +SPIRVEntry::decode(std::istream &I) { + assert (0 && "Not implemented"); +} + +std::vector<SPIRVValue *> +SPIRVEntry::getValues(const std::vector<SPIRVId>& IdVec)const { + std::vector<SPIRVValue *> ValueVec; + for (auto i:IdVec) + ValueVec.push_back(getValue(i)); + return ValueVec; +} + +std::vector<SPIRVType *> +SPIRVEntry::getValueTypes(const std::vector<SPIRVId>& IdVec)const { + std::vector<SPIRVType *> TypeVec; + for (auto i:IdVec) + TypeVec.push_back(getValue(i)->getType()); + return TypeVec; +} + +std::vector<SPIRVId> +SPIRVEntry::getIds(const std::vector<SPIRVValue *> ValueVec)const { + std::vector<SPIRVId> IdVec; + for (auto i:ValueVec) + IdVec.push_back(i->getId()); + return IdVec; +} + +SPIRVEntry * +SPIRVEntry::getEntry(SPIRVId TheId) const { + return Module->getEntry(TheId); +} + +void +SPIRVEntry::validateFunctionControlMask(SPIRVWord TheFCtlMask) + const { + SPIRVCK(isValidFunctionControlMask(TheFCtlMask), + InvalidFunctionControlMask, ""); +} + +void +SPIRVEntry::validateValues(const std::vector<SPIRVId> &Ids)const { + for (auto I:Ids) + getValue(I)->validate(); +} + +void +SPIRVEntry::validateBuiltin(SPIRVWord TheSet, SPIRVWord Index)const { + assert(TheSet != SPIRVWORD_MAX && Index != SPIRVWORD_MAX && + "Invalid builtin"); +} + +void +SPIRVEntry::addDecorate(SPIRVDecorate *Dec) { + auto Kind = Dec->getDecorateKind(); + Decorates.insert(std::make_pair(Dec->getDecorateKind(), Dec)); + Module->addDecorate(Dec); + if (Kind == spv::DecorationLinkageAttributes) { + auto *LinkageAttr = static_cast<const SPIRVDecorateLinkageAttr*>(Dec); + setName(LinkageAttr->getLinkageName()); + } + SPIRVDBG(spvdbgs() << "[addDecorate] " << *Dec << '\n';) +} + +void +SPIRVEntry::addDecorate(Decoration Kind) { + addDecorate(new SPIRVDecorate(Kind, this)); +} + +void +SPIRVEntry::addDecorate(Decoration Kind, SPIRVWord Literal) { + addDecorate(new SPIRVDecorate(Kind, this, Literal)); +} + +void +SPIRVEntry::eraseDecorate(Decoration Dec){ + Decorates.erase(Dec); +} + +void +SPIRVEntry::takeDecorates(SPIRVEntry *E){ + Decorates = std::move(E->Decorates); + SPIRVDBG(spvdbgs() << "[takeDecorates] " << Id << '\n';) +} + +void +SPIRVEntry::setLine(const std::shared_ptr<const SPIRVLine>& L){ + Line = L; + SPIRVDBG(spvdbgs() << "[setLine] " << *L << '\n';) +} + +void +SPIRVEntry::addMemberDecorate(SPIRVMemberDecorate *Dec){ + assert(canHaveMemberDecorates() && MemberDecorates.find(Dec->getPair()) == + MemberDecorates.end()); + MemberDecorates[Dec->getPair()] = Dec; + Module->addDecorate(Dec); + SPIRVDBG(spvdbgs() << "[addMemberDecorate] " << *Dec << '\n';) +} + +void +SPIRVEntry::addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind) { + addMemberDecorate(new SPIRVMemberDecorate(Kind, MemberNumber, this)); +} + +void +SPIRVEntry::addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind, + SPIRVWord Literal) { + addMemberDecorate(new SPIRVMemberDecorate(Kind, MemberNumber, this, Literal)); +} + +void +SPIRVEntry::eraseMemberDecorate(SPIRVWord MemberNumber, Decoration Dec){ + MemberDecorates.erase(std::make_pair(MemberNumber, Dec)); +} + +void +SPIRVEntry::takeMemberDecorates(SPIRVEntry *E){ + MemberDecorates = std::move(E->MemberDecorates); + SPIRVDBG(spvdbgs() << "[takeMemberDecorates] " << Id << '\n';) +} + +void +SPIRVEntry::takeAnnotations(SPIRVForward *E){ + Module->setName(this, E->getName()); + takeDecorates(E); + takeMemberDecorates(E); + if (OpCode == OpFunction) + static_cast<SPIRVFunction *>(this)->takeExecutionModes(E); +} + +// Check if an entry has Kind of decoration and get the literal of the +// first decoration of such kind at Index. +bool +SPIRVEntry::hasDecorate(Decoration Kind, size_t Index, SPIRVWord *Result)const { + DecorateMapType::const_iterator Loc = Decorates.find(Kind); + if (Loc == Decorates.end()) + return false; + if (Result) + *Result = Loc->second->getLiteral(Index); + return true; +} + +// Get literals of all decorations of Kind at Index. +std::set<SPIRVWord> +SPIRVEntry::getDecorate(Decoration Kind, size_t Index) const { + auto Range = Decorates.equal_range(Kind); + std::set<SPIRVWord> Value; + for (auto I = Range.first, E = Range.second; I != E; ++I) { + assert(Index < I->second->getLiteralCount() && "Invalid index"); + Value.insert(I->second->getLiteral(Index)); + } + return Value; +} + +bool +SPIRVEntry::hasLinkageType() const { + return OpCode == OpFunction || OpCode == OpVariable; +} + +void +SPIRVEntry::encodeDecorate(spv_ostream &O) const { + for (auto& i:Decorates) + O << *i.second; +} + +SPIRVLinkageTypeKind +SPIRVEntry::getLinkageType() const { + assert(hasLinkageType()); + DecorateMapType::const_iterator Loc = Decorates.find(DecorationLinkageAttributes); + if (Loc == Decorates.end()) + return LinkageTypeInternal; + return static_cast<const SPIRVDecorateLinkageAttr*>(Loc->second)->getLinkageType(); +} + +void +SPIRVEntry::setLinkageType(SPIRVLinkageTypeKind LT) { + assert(isValid(LT)); + assert(hasLinkageType()); + addDecorate(new SPIRVDecorateLinkageAttr(this, Name, LT)); +} + +void +SPIRVEntry::updateModuleVersion() const { + if (!Module) + return; + + Module->setMinSPIRVVersion(getRequiredSPIRVVersion()); +} + +spv_ostream & +operator<<(spv_ostream &O, const SPIRVEntry &E) { + E.validate(); + E.encodeAll(O); + O << SPIRVNL(); + return O; +} + +std::istream & +operator>>(std::istream &I, SPIRVEntry &E) { + E.decode(I); + return I; +} + +SPIRVEntryPoint::SPIRVEntryPoint(SPIRVModule *TheModule, + SPIRVExecutionModelKind TheExecModel, SPIRVId TheId, + const std::string &TheName) + :SPIRVAnnotation(TheModule->get<SPIRVFunction>(TheId), + getSizeInWords(TheName) + 3), ExecModel(TheExecModel), Name(TheName){ +} + +void +SPIRVEntryPoint::encode(spv_ostream &O) const { + getEncoder(O) << ExecModel << Target << Name; +} + +void +SPIRVEntryPoint::decode(std::istream &I) { + getDecoder(I) >> ExecModel >> Target >> Name; + Module->setName(getOrCreateTarget(), Name); + Module->addEntryPoint(ExecModel, Target); +} + +void +SPIRVExecutionMode::encode(spv_ostream &O) const { + getEncoder(O) << Target << ExecMode << WordLiterals; +} + +void +SPIRVExecutionMode::decode(std::istream &I) { + getDecoder(I) >> Target >> ExecMode; + switch(ExecMode) { + case ExecutionModeLocalSize: + case ExecutionModeLocalSizeHint: + WordLiterals.resize(3); + break; + case ExecutionModeInvocations: + case ExecutionModeOutputVertices: + case ExecutionModeVecTypeHint: + WordLiterals.resize(1); + break; + default: + // Do nothing. Keep this to avoid VS2013 warning. + break; + } + getDecoder(I) >> WordLiterals; + getOrCreateTarget()->addExecutionMode(this); +} + +SPIRVForward * +SPIRVAnnotationGeneric::getOrCreateTarget()const { + SPIRVEntry *Entry = nullptr; + bool Found = Module->exist(Target, &Entry); + assert((!Found || Entry->getOpCode() == OpForward) && + "Annotations only allowed on forward"); + if (!Found) + Entry = Module->addForward(Target, nullptr); + return static_cast<SPIRVForward *>(Entry); +} + +SPIRVName::SPIRVName(const SPIRVEntry *TheTarget, const std::string& TheStr) + :SPIRVAnnotation(TheTarget, getSizeInWords(TheStr) + 2), Str(TheStr){ +} + +void +SPIRVName::encode(spv_ostream &O) const { + getEncoder(O) << Target << Str; +} + +void +SPIRVName::decode(std::istream &I) { + getDecoder(I) >> Target >> Str; + Module->setName(getOrCreateTarget(), Str); +} + +void +SPIRVName::validate() const { + assert(WordCount == getSizeInWords(Str) + 2 && "Incorrect word count"); +} + +_SPIRV_IMP_ENCDEC2(SPIRVString, Id, Str) +_SPIRV_IMP_ENCDEC3(SPIRVMemberName, Target, MemberNumber, Str) + +void +SPIRVLine::encode(spv_ostream &O) const { + getEncoder(O) << FileName << Line << Column; +} + +void +SPIRVLine::decode(std::istream &I) { + getDecoder(I) >> FileName >> Line >> Column; + std::shared_ptr<const SPIRVLine> L(this); + Module->setCurrentLine(L); +} + +void +SPIRVLine::validate() const { + assert(OpCode == OpLine); + assert(WordCount == 4); + assert(get<SPIRVEntry>(FileName)->getOpCode() == OpString); + assert(Line != SPIRVWORD_MAX); + assert(Column != SPIRVWORD_MAX); + assert(!hasId()); +} + +void +SPIRVMemberName::validate() const { + assert(OpCode == OpMemberName); + assert(WordCount == getSizeInWords(Str) + FixedWC); + assert(get<SPIRVEntry>(Target)->getOpCode() == OpTypeStruct); + assert(MemberNumber < get<SPIRVTypeStruct>(Target)->getStructMemberCount()); +} + +SPIRVExtInstImport::SPIRVExtInstImport(SPIRVModule *TheModule, SPIRVId TheId, + const std::string &TheStr): + SPIRVEntry(TheModule, 2 + getSizeInWords(TheStr), OC, TheId), Str(TheStr){ + validate(); +} + +void +SPIRVExtInstImport::encode(spv_ostream &O) const { + getEncoder(O) << Id << Str; +} + +void +SPIRVExtInstImport::decode(std::istream &I) { + getDecoder(I) >> Id >> Str; + Module->importBuiltinSetWithId(Str, Id); +} + +void +SPIRVExtInstImport::validate() const { + SPIRVEntry::validate(); + assert(!Str.empty() && "Invalid builtin set"); +} + +void +SPIRVMemoryModel::encode(spv_ostream &O) const { + getEncoder(O) << Module->getAddressingModel() << + Module->getMemoryModel(); +} + +void +SPIRVMemoryModel::decode(std::istream &I) { + SPIRVAddressingModelKind AddrModel; + SPIRVMemoryModelKind MemModel; + getDecoder(I) >> AddrModel >> MemModel; + Module->setAddressingModel(AddrModel); + Module->setMemoryModel(MemModel); +} + +void +SPIRVMemoryModel::validate() const { + auto AM = Module->getAddressingModel(); + auto MM = Module->getMemoryModel(); + SPIRVCK(isValid(AM), InvalidAddressingModel, "Actual is "+AM ); + SPIRVCK(isValid(MM), InvalidMemoryModel, "Actual is "+MM); +} + +void +SPIRVSource::encode(spv_ostream &O) const { + SPIRVWord Ver = SPIRVWORD_MAX; + auto Language = Module->getSourceLanguage(&Ver); + getEncoder(O) << Language << Ver; +} + +void +SPIRVSource::decode(std::istream &I) { + SourceLanguage Lang = SourceLanguageUnknown; + SPIRVWord Ver = SPIRVWORD_MAX; + getDecoder(I) >> Lang >> Ver; + Module->setSourceLanguage(Lang, Ver); +} + +SPIRVSourceExtension::SPIRVSourceExtension(SPIRVModule *M, + const std::string &SS) + :SPIRVEntryNoId(M, 1 + getSizeInWords(SS)), S(SS){} + +void +SPIRVSourceExtension::encode(spv_ostream &O) const { + getEncoder(O) << S; +} + +void +SPIRVSourceExtension::decode(std::istream &I) { + getDecoder(I) >> S; + Module->getSourceExtension().insert(S); +} + +SPIRVExtension::SPIRVExtension(SPIRVModule *M, const std::string &SS) + :SPIRVEntryNoId(M, 1 + getSizeInWords(SS)), S(SS){} + +void +SPIRVExtension::encode(spv_ostream &O) const { + getEncoder(O) << S; +} + +void +SPIRVExtension::decode(std::istream &I) { + getDecoder(I) >> S; + Module->getExtension().insert(S); +} + +SPIRVCapability::SPIRVCapability(SPIRVModule *M, SPIRVCapabilityKind K) + :SPIRVEntryNoId(M, 2), Kind(K){ + updateModuleVersion(); +} + +void +SPIRVCapability::encode(spv_ostream &O) const { + getEncoder(O) << Kind; +} + +void +SPIRVCapability::decode(std::istream &I) { + getDecoder(I) >> Kind; + Module->addCapability(Kind); +} + +} // namespace SPIRV + diff --git a/lib/SPIRV/libSPIRV/SPIRVEntry.h b/lib/SPIRV/libSPIRV/SPIRVEntry.h index 6a935d7..43f19b3 100644 --- a/lib/SPIRV/libSPIRV/SPIRVEntry.h +++ b/lib/SPIRV/libSPIRV/SPIRVEntry.h @@ -1,782 +1,782 @@ -//===- SPIRVEntry.h - Base Class for SPIR-V Entities -------------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines the base class for SPIRV entities.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVENTRY_HPP_
-#define SPIRVENTRY_HPP_
-
-#include "SPIRVEnum.h"
-#include "SPIRVIsValidEnum.h"
-#include "SPIRVError.h"
-#include <cassert>
-#include <iostream>
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-namespace SPIRV{
-
-class SPIRVModule;
-class SPIRVEncoder;
-class SPIRVDecoder;
-class SPIRVType;
-class SPIRVValue;
-class SPIRVDecorate;
-class SPIRVForward;
-class SPIRVMemberDecorate;
-class SPIRVLine;
-class SPIRVString;
-class SPIRVExtInst;
-
-// Add declaration of encode/decode functions to a class.
-// Used inside class definition.
-#define _SPIRV_DCL_ENCDEC \
- void encode(spv_ostream &O) const; \
- void decode(std::istream &I);
-
-#define _REQ_SPIRV_VER(Version) \
- SPIRVWord getRequiredSPIRVVersion() const override { return Version; }
-
-// Add implementation of encode/decode functions to a class.
-// Used out side of class definition.
-#define _SPIRV_IMP_ENCDEC0(Ty) \
- void Ty::encode(spv_ostream &O) const {} \
- void Ty::decode(std::istream &I) {}
-#define _SPIRV_IMP_ENCDEC1(Ty,x) \
- void Ty::encode(spv_ostream &O) const { getEncoder(O) << x; } \
- void Ty::decode(std::istream &I) { getDecoder(I) >> x;}
-#define _SPIRV_IMP_ENCDEC2(Ty,x,y) \
- void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y; } \
- void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y;}
-#define _SPIRV_IMP_ENCDEC3(Ty,x,y,z) \
- void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z; } \
- void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z;}
-#define _SPIRV_IMP_ENCDEC4(Ty,x,y,z,u) \
- void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z << \
- u; } \
- void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u;}
-#define _SPIRV_IMP_ENCDEC5(Ty,x,y,z,u,v) \
- void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z << \
- u << v; } \
- void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v;}
-#define _SPIRV_IMP_ENCDEC6(Ty,x,y,z,u,v,w) \
- void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z << \
- u << v << w; } \
- void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> \
- v >> w;}
-#define _SPIRV_IMP_ENCDEC7(Ty,x,y,z,u,v,w,r) \
- void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z << \
- u << v << w << r; } \
- void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> \
- v >> w >> r;}
-#define _SPIRV_IMP_ENCDEC8(Ty,x,y,z,u,v,w,r,s) \
- void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z << \
- u << v << w << r << s; } \
- void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> \
- v >> w >> r >> s;}
-#define _SPIRV_IMP_ENCDEC9(Ty,x,y,z,u,v,w,r,s,t) \
- void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z << \
- u << v << w << r << s << t; } \
- void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> \
- v >> w >> r >> s >> t;}
-
-// Add definition of encode/decode functions to a class.
-// Used inside class definition.
-#define _SPIRV_DEF_ENCDEC0 \
- void encode(spv_ostream &O) const {} \
- void decode(std::istream &I) {}
-#define _SPIRV_DEF_ENCDEC1(x) \
- void encode(spv_ostream &O) const { getEncoder(O) << x; } \
- void decode(std::istream &I) { getDecoder(I) >> x;}
-#define _SPIRV_DEF_ENCDEC2(x,y) \
- void encode(spv_ostream &O) const { getEncoder(O) << x << y; } \
- void decode(std::istream &I) { getDecoder(I) >> x >> y;}
-#define _SPIRV_DEF_ENCDEC3(x,y,z) \
- void encode(spv_ostream &O) const { getEncoder(O) << x << y << z; } \
- void decode(std::istream &I) { getDecoder(I) >> x >> y >> z;}
-#define _SPIRV_DEF_ENCDEC4(x,y,z,u) \
- void encode(spv_ostream &O) const { getEncoder(O) << x << y << z << u; } \
- void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u;}
-#define _SPIRV_DEF_ENCDEC5(x,y,z,u,v) \
- void encode(spv_ostream &O) const { getEncoder(O) << x << y << z << u << \
- v; } \
- void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v;}
-#define _SPIRV_DEF_ENCDEC6(x,y,z,u,v,w) \
- void encode(spv_ostream &O) const { getEncoder(O) << x << y << z << u << \
- v << w; } \
- void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> w;}
-#define _SPIRV_DEF_ENCDEC7(x,y,z,u,v,w,r) \
- void encode(spv_ostream &O) const { getEncoder(O) << x << y << z << u << \
- v << w << r; } \
- void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> \
- w >> r;}
-#define _SPIRV_DEF_ENCDEC8(x,y,z,u,v,w,r,s) \
- void encode(spv_ostream &O) const { getEncoder(O) << x << y << z << u << \
- v << w << r << s; } \
- void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> \
- w >> r >> s;}
-#define _SPIRV_DEF_ENCDEC9(x,y,z,u,v,w,r,s,t) \
- void encode(spv_ostream &O) const { getEncoder(O) << x << y << z << u << \
- v << w << r << s << t; } \
- void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> \
- w >> r >> s >> t;}
-
-/// All SPIR-V in-memory-representation entities inherits from SPIRVEntry.
-/// Usually there are two flavors of constructors of SPIRV objects:
-///
-/// 1. complete constructor: It requires all the parameters needed to create a
-/// SPIRV entity with complete information which can be validated. It is
-/// usually used by LLVM/SPIR-V translator to create SPIRV object
-/// corresponding to LLVM object. Such constructor calls validate() at
-/// the end of the construction.
-///
-/// 2. incomplete constructor: For leaf classes, it has no parameters.
-/// It is usually called by SPIRVEntry::make(opcode) to create an incomplete
-/// object which should not be validated. Then setWordCount(count) is
-/// called to fix the size of the object if it is variable, and then the
-/// information is filled by the virtual function decode(istream).
-/// After that the object can be validated.
-///
-/// To add a new SPIRV class:
-///
-/// 1. It is recommended to name the class as SPIRVXXX if it has a fixed op code
-/// OpXXX. Although it is not mandatory, doing this facilitates adding it to
-/// the table of the factory function SPIRVEntry::create().
-/// 2. Inherit from proper SPIRV class such as SPIRVType, SPIRVValue,
-/// SPIRVInstruction, etc.
-/// 3. Implement virtual function encode(), decode(), validate().
-/// 4. If the object has variable size, implement virtual function
-/// setWordCount().
-/// 5. If the class has special attributes, e.g. having no id, or having no
-/// type as a value, set them in the constructors.
-/// 6. If the class may represent SPIRV entity which has been added in version
-/// later than 1.0, implement virtual function getRequiredSPIRVVersion().
-/// To automaticly update module's version you can also call protected
-/// function updateModuleVersion() in the constructor.
-/// 7. Add the class to the Table of SPIRVEntry::create().
-/// 8. Add the class to SPIRVToLLVM and LLVMToSPIRV.
-
-class SPIRVEntry {
-public:
- enum SPIRVEntryAttrib {
- SPIRVEA_DEFAULT = 0,
- SPIRVEA_NOID = 1, // Entry has no valid id
- SPIRVEA_NOTYPE = 2, // Value has no type
- };
-
- // Complete constructor for objects with id
- SPIRVEntry(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
- SPIRVId TheId)
- :Module(M), OpCode(TheOpCode), Id(TheId), Attrib(SPIRVEA_DEFAULT),
- WordCount(TheWordCount), Line(nullptr){
- validate();
- }
-
- // Complete constructor for objects without id
- SPIRVEntry(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode)
- :Module(M), OpCode(TheOpCode), Id(SPIRVID_INVALID), Attrib(SPIRVEA_NOID),
- WordCount(TheWordCount), Line(nullptr){
- validate();
- }
-
- // Incomplete constructor
- SPIRVEntry(Op TheOpCode)
- :Module(NULL), OpCode(TheOpCode), Id(SPIRVID_INVALID),
- Attrib(SPIRVEA_DEFAULT), WordCount(0), Line(nullptr){}
-
- SPIRVEntry()
- :Module(NULL), OpCode(OpNop), Id(SPIRVID_INVALID),
- Attrib(SPIRVEA_DEFAULT), WordCount(0), Line(nullptr){}
-
-
- virtual ~SPIRVEntry(){}
-
- bool exist(SPIRVId)const;
- template<class T>
- T* get(SPIRVId TheId)const { return static_cast<T*>(getEntry(TheId));}
- SPIRVEntry *getEntry(SPIRVId) const;
- SPIRVEntry *getOrCreate(SPIRVId TheId) const;
- SPIRVValue *getValue(SPIRVId TheId)const;
- std::vector<SPIRVValue *> getValues(const std::vector<SPIRVId>&)const;
- std::vector<SPIRVId> getIds(const std::vector<SPIRVValue *>)const;
- SPIRVType *getValueType(SPIRVId TheId)const;
- std::vector<SPIRVType *> getValueTypes(const std::vector<SPIRVId>&)const;
-
- virtual SPIRVDecoder getDecoder(std::istream &);
- virtual SPIRVEncoder getEncoder(spv_ostream &)const;
- SPIRVErrorLog &getErrorLog()const;
- SPIRVId getId() const { assert(hasId()); return Id;}
- std::shared_ptr<const SPIRVLine> getLine() const { return Line;}
- SPIRVLinkageTypeKind getLinkageType() const;
- Op getOpCode() const { return OpCode;}
- SPIRVModule *getModule() const { return Module;}
- virtual SPIRVCapVec getRequiredCapability() const { return SPIRVCapVec();}
- const std::string& getName() const { return Name;}
- bool hasDecorate(Decoration Kind, size_t Index = 0,
- SPIRVWord *Result=0)const;
- std::set<SPIRVWord> getDecorate(Decoration Kind, size_t Index = 0)const;
- bool hasId() const { return !(Attrib & SPIRVEA_NOID);}
- bool hasLine() const { return Line != nullptr;}
- bool hasLinkageType() const;
- bool isAtomic() const { return isAtomicOpCode(OpCode);}
- bool isBasicBlock() const { return isLabel();}
- bool isBuiltinCall() const { return OpCode == OpExtInst;}
- bool isDecorate()const { return OpCode == OpDecorate;}
- bool isMemberDecorate()const { return OpCode == OpMemberDecorate;}
- bool isForward() const { return OpCode == OpForward;}
- bool isLabel() const { return OpCode == OpLabel;}
- bool isUndef() const { return OpCode == OpUndef;}
- bool isControlBarrier() const { return OpCode == OpControlBarrier;}
- bool isMemoryBarrier() const { return OpCode == OpMemoryBarrier;}
- bool isVariable() const { return OpCode == OpVariable;}
- bool isEndOfBlock() const;
- virtual bool isInst() const { return false;}
- virtual bool isOperandLiteral(unsigned Index) const {
- assert(0 && "not implemented");
- return false;
- }
-
- void addDecorate(SPIRVDecorate *);
- void addDecorate(Decoration Kind);
- void addDecorate(Decoration Kind, SPIRVWord Literal);
- void eraseDecorate(Decoration);
- void addMemberDecorate(SPIRVMemberDecorate *);
- void addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind);
- void addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind,
- SPIRVWord Literal);
- void eraseMemberDecorate(SPIRVWord MemberNumber, Decoration Kind);
- void setHasNoId() { Attrib |= SPIRVEA_NOID;}
- void setId(SPIRVId TheId) { Id = TheId;}
- void setLine(const std::shared_ptr<const SPIRVLine>& L);
- void setLinkageType(SPIRVLinkageTypeKind);
- void setModule(SPIRVModule *TheModule);
- void setName(const std::string& TheName);
- virtual void setScope(SPIRVEntry *Scope){};
- void takeAnnotations(SPIRVForward *);
- void takeDecorates(SPIRVEntry *);
- void takeMemberDecorates(SPIRVEntry *);
-
- /// After a SPIRV entry is created during reading SPIRV binary by default
- /// constructor, this function is called to allow the SPIRV entry to resize
- /// its variable sized member before decoding the remaining words.
- virtual void setWordCount(SPIRVWord TheWordCount);
-
- /// Create an empty SPIRV object by op code, e.g. OpTypeInt creates
- /// SPIRVTypeInt.
- static SPIRVEntry *create(Op);
- static std::unique_ptr<SPIRVEntry> create_unique(Op);
-
- /// Create an empty extended instruction.
- static std::unique_ptr<SPIRVExtInst> create_unique(
- SPIRVExtInstSetKind Set,
- unsigned ExtOp);
-
- friend spv_ostream &operator<<(spv_ostream &O, const SPIRVEntry &E);
- friend std::istream &operator>>(std::istream &I, SPIRVEntry &E);
- virtual void encodeLine(spv_ostream &O) const;
- virtual void encodeAll(spv_ostream &O) const;
- virtual void encodeName(spv_ostream &O) const;
- virtual void encodeChildren(spv_ostream &O)const;
- virtual void encodeDecorate(spv_ostream &O)const;
- virtual void encodeWordCountOpCode(spv_ostream &O)const;
- virtual void encode(spv_ostream &O) const;
- virtual void decode(std::istream &I);
-
- friend class SPIRVDecoder;
-
- /// Checks the integrity of the object.
- virtual void validate()const {
- assert(Module && "Invalid module");
- assert(OpCode != OpNop && "Invalid op code");
- assert((!hasId() || isValidId(Id)) && "Invalid Id");
- }
- void validateFunctionControlMask(SPIRVWord FCtlMask)const;
- void validateValues(const std::vector<SPIRVId> &)const;
- void validateBuiltin(SPIRVWord, SPIRVWord)const;
-
- // By default assume SPIRV 1.0 as required version
- virtual SPIRVWord getRequiredSPIRVVersion() const { return SPIRV_1_0; }
-
- virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const {
- return std::vector<SPIRVEntry*>();
- }
-
-protected:
- /// An entry may have multiple FuncParamAttr decorations.
- typedef std::multimap<Decoration, const SPIRVDecorate*> DecorateMapType;
- typedef std::map<std::pair<SPIRVWord, Decoration>,
- const SPIRVMemberDecorate*> MemberDecorateMapType;
-
- bool canHaveMemberDecorates() const {
- return OpCode == OpTypeStruct ||
- OpCode == OpForward;
- }
- MemberDecorateMapType& getMemberDecorates() {
- assert(canHaveMemberDecorates());
- return MemberDecorates;
- }
-
- void updateModuleVersion() const;
-
- SPIRVModule *Module;
- Op OpCode;
- SPIRVId Id;
- std::string Name;
- unsigned Attrib;
- SPIRVWord WordCount;
-
- DecorateMapType Decorates;
- MemberDecorateMapType MemberDecorates;
- std::shared_ptr<const SPIRVLine> Line;
-};
-
-class SPIRVEntryNoIdGeneric:public SPIRVEntry {
-public:
- SPIRVEntryNoIdGeneric(SPIRVModule *M, unsigned TheWordCount, Op OC)
- :SPIRVEntry(M, TheWordCount, OC){
- setAttr();
- }
- SPIRVEntryNoIdGeneric(Op OC):SPIRVEntry(OC){
- setAttr();
- }
-protected:
- void setAttr() {
- setHasNoId();
- }
-};
-
-template<Op OC>
-class SPIRVEntryNoId:public SPIRVEntryNoIdGeneric {
-public:
- SPIRVEntryNoId(SPIRVModule *M, unsigned TheWordCount)
- :SPIRVEntryNoIdGeneric(M, TheWordCount, OC){}
- SPIRVEntryNoId():SPIRVEntryNoIdGeneric(OC){}
-};
-
-template<Op TheOpCode>
-class SPIRVEntryOpCodeOnly:public SPIRVEntryNoId<TheOpCode> {
-public:
- SPIRVEntryOpCodeOnly(){
- SPIRVEntry::WordCount = 1;
- validate();
- }
-protected:
- _SPIRV_DEF_ENCDEC0
- void validate()const {
- assert(isValidId(SPIRVEntry::OpCode));
- }
-};
-
-class SPIRVAnnotationGeneric:public SPIRVEntryNoIdGeneric {
-public:
- // Complete constructor
- SPIRVAnnotationGeneric(SPIRVModule *TheModule, unsigned TheWordCount, Op OC,
- SPIRVId TheTarget = SPIRVID_INVALID)
- : SPIRVEntryNoIdGeneric(TheModule, TheWordCount, OC), Target(TheTarget) {}
- // Incomplete constructor
- SPIRVAnnotationGeneric(Op OC):SPIRVEntryNoIdGeneric(OC),
- Target(SPIRVID_INVALID){}
-
- SPIRVId getTargetId()const { return Target;}
- SPIRVForward *getOrCreateTarget()const;
- void setTargetId(SPIRVId T) { Target = T;}
-protected:
- SPIRVId Target;
-};
-
-template<Op OC>
-class SPIRVAnnotation:public SPIRVAnnotationGeneric {
-public:
- // Complete constructor
- SPIRVAnnotation(const SPIRVEntry *TheTarget, unsigned TheWordCount)
- : SPIRVAnnotationGeneric(TheTarget->getModule(), TheWordCount, OC,
- TheTarget->getId()) {}
- // Incomplete constructor
- SPIRVAnnotation():SPIRVAnnotationGeneric(OC){}
-};
-
-class SPIRVEntryPoint:public SPIRVAnnotation<OpEntryPoint> {
-public:
- SPIRVEntryPoint(SPIRVModule *TheModule, SPIRVExecutionModelKind,
- SPIRVId TheId, const std::string &TheName);
- SPIRVEntryPoint():ExecModel(ExecutionModelKernel){}
- _SPIRV_DCL_ENCDEC
-protected:
- SPIRVExecutionModelKind ExecModel;
- std::string Name;
-};
-
-
-class SPIRVName:public SPIRVAnnotation<OpName> {
-public:
- // Complete constructor
- SPIRVName(const SPIRVEntry *TheTarget, const std::string& TheStr);
- // Incomplete constructor
- SPIRVName(){}
-protected:
- _SPIRV_DCL_ENCDEC
- void validate() const;
-
- std::string Str;
-};
-
-class SPIRVMemberName:public SPIRVAnnotation<OpName> {
-public:
- static const SPIRVWord FixedWC = 3;
- // Complete constructor
- SPIRVMemberName(const SPIRVEntry *TheTarget, SPIRVWord TheMemberNumber,
- const std::string& TheStr)
- :SPIRVAnnotation(TheTarget, FixedWC + getSizeInWords(TheStr)),
- MemberNumber(TheMemberNumber), Str(TheStr){
- validate();
- }
- // Incomplete constructor
- SPIRVMemberName():MemberNumber(SPIRVWORD_MAX){}
-protected:
- _SPIRV_DCL_ENCDEC
- void validate() const;
- SPIRVWord MemberNumber;
- std::string Str;
-};
-
-class SPIRVString:public SPIRVEntry {
- static const Op OC = OpString;
- static const SPIRVWord FixedWC = 2;
-public:
- SPIRVString(SPIRVModule *M, SPIRVId TheId, const std::string &TheStr)
- :SPIRVEntry(M, FixedWC + getSizeInWords(TheStr), OC, TheId), Str(TheStr){}
- SPIRVString():SPIRVEntry(OC){}
- _SPIRV_DCL_ENCDEC
- const std::string &getStr()const { return Str;}
-protected:
- std::string Str;
-};
-
-class SPIRVLine: public SPIRVEntry {
-public:
- static const SPIRVWord WC = 4;
- // Complete constructor
- SPIRVLine(SPIRVModule *M, SPIRVId TheFileName, SPIRVWord TheLine,
- SPIRVWord TheColumn)
- :SPIRVEntry(M, WC, OpLine),
- FileName(TheFileName),
- Line(TheLine),
- Column(TheColumn) {
- Attrib = SPIRVEA_NOID | SPIRVEA_NOTYPE;
- validate();
- }
- // Incomplete constructor
- SPIRVLine():SPIRVEntry(OpLine), FileName(SPIRVID_INVALID), Line(SPIRVWORD_MAX),
- Column(SPIRVWORD_MAX) {
- Attrib = SPIRVEA_NOID | SPIRVEA_NOTYPE;
- }
-
- SPIRVWord getColumn() const {
- return Column;
- }
-
- void setColumn(const SPIRVWord column) {
- Column = column;
- }
-
- SPIRVId getFileName() const {
- return FileName;
- }
-
- const std::string &getFileNameStr() const {
- return get<SPIRVString>(FileName)->getStr();
- }
-
- void setFileName(const SPIRVId fileName) {
- FileName = fileName;
- }
-
- SPIRVWord getLine() const {
- return Line;
- }
-
- void setLine(const SPIRVWord line) {
- Line = line;
- }
-
- bool operator!=(const SPIRVLine &O) const {
- return !equals(O.FileName, O.Line, O.Column);
- }
-
- bool equals(const SPIRVId TheFileName,
- const SPIRVWord TheLine,
- const SPIRVWord TheColumn) const {
- return FileName == TheFileName && Line == TheLine && Column == TheColumn;
- }
-
-protected:
- _SPIRV_DCL_ENCDEC
- void validate() const;
- SPIRVId FileName;
- SPIRVWord Line;
- SPIRVWord Column;
-};
-
-class SPIRVExecutionMode:public SPIRVAnnotation<OpExecutionMode> {
-public:
- // Complete constructor for LocalSize, LocalSizeHint
- SPIRVExecutionMode(SPIRVEntry *TheTarget, SPIRVExecutionModeKind TheExecMode,
- SPIRVWord x, SPIRVWord y, SPIRVWord z)
- :SPIRVAnnotation(TheTarget, 6), ExecMode(TheExecMode){
- WordLiterals.push_back(x);
- WordLiterals.push_back(y);
- WordLiterals.push_back(z);
- updateModuleVersion();
- }
- // Complete constructor for VecTypeHint, SubgroupSize, SubgroupsPerWorkgroup
- SPIRVExecutionMode(SPIRVEntry *TheTarget, SPIRVExecutionModeKind TheExecMode,
- SPIRVWord code)
- :SPIRVAnnotation(TheTarget, 4), ExecMode(TheExecMode){
- WordLiterals.push_back(code);
- updateModuleVersion();
- }
- // Complete constructor for ContractionOff
- SPIRVExecutionMode(SPIRVEntry *TheTarget, SPIRVExecutionModeKind TheExecMode)
- :SPIRVAnnotation(TheTarget, 3), ExecMode(TheExecMode){
- updateModuleVersion();
- }
- // Incomplete constructor
- SPIRVExecutionMode():ExecMode(ExecutionModeInvocations){}
- SPIRVExecutionModeKind getExecutionMode()const { return ExecMode;}
- const std::vector<SPIRVWord>& getLiterals()const { return WordLiterals;}
- SPIRVCapVec getRequiredCapability() const {
- return getCapability(ExecMode);
- }
-
- SPIRVWord getRequiredSPIRVVersion() const override {
- switch (ExecMode) {
- case ExecutionModeFinalizer:
- case ExecutionModeInitializer:
- case ExecutionModeSubgroupSize:
- case ExecutionModeSubgroupsPerWorkgroup:
- return SPIRV_1_1;
-
- default:
- return SPIRV_1_0;
- }
- }
-
-protected:
- _SPIRV_DCL_ENCDEC
- SPIRVExecutionModeKind ExecMode;
- std::vector<SPIRVWord> WordLiterals;
-};
-
-
-class SPIRVComponentExecutionModes {
- typedef std::map<SPIRVExecutionModeKind, SPIRVExecutionMode*>
- SPIRVExecutionModeMap;
-public:
- void addExecutionMode(SPIRVExecutionMode *ExecMode) {
- ExecModes[ExecMode->getExecutionMode()] = ExecMode;
- }
- SPIRVExecutionMode *getExecutionMode(SPIRVExecutionModeKind EMK)const {
- auto Loc = ExecModes.find(EMK);
- if (Loc == ExecModes.end())
- return nullptr;
- return Loc->second;
- }
-protected:
- SPIRVExecutionModeMap ExecModes;
-};
-
-class SPIRVExtInstImport:public SPIRVEntry {
-public:
- const static Op OC = OpExtInstImport;
- // Complete constructor
- SPIRVExtInstImport(SPIRVModule *TheModule, SPIRVId TheId,
- const std::string& TheStr);
- // Incomplete constructor
- SPIRVExtInstImport():SPIRVEntry(OC){}
-protected:
- _SPIRV_DCL_ENCDEC
- void validate() const;
-
- std::string Str;
-};
-
-class SPIRVMemoryModel:public SPIRVEntryNoId<OpMemoryModel> {
-public:
- SPIRVMemoryModel(SPIRVModule *M):SPIRVEntryNoId(M, 3){}
- SPIRVMemoryModel(){}
- _SPIRV_DCL_ENCDEC
- void validate() const;
-};
-
-class SPIRVSource:public SPIRVEntryNoId<OpSource> {
-public:
- SPIRVSource(SPIRVModule *M):SPIRVEntryNoId(M, 3){}
- SPIRVSource(){}
- _SPIRV_DCL_ENCDEC
-};
-
-class SPIRVSourceExtension:public SPIRVEntryNoId<OpSourceExtension> {
-public:
- SPIRVSourceExtension(SPIRVModule *M, const std::string &SS);
- SPIRVSourceExtension(){}
- _SPIRV_DCL_ENCDEC
-private:
- std::string S;
-};
-
-class SPIRVExtension:public SPIRVEntryNoId<OpExtension> {
-public:
- SPIRVExtension(SPIRVModule *M, const std::string &SS);
- SPIRVExtension(){}
- _SPIRV_DCL_ENCDEC
-private:
- std::string S;
-};
-
-class SPIRVCapability:public SPIRVEntryNoId<OpCapability> {
-public:
- SPIRVCapability(SPIRVModule *M, SPIRVCapabilityKind K);
- SPIRVCapability():Kind(CapabilityMatrix){}
- _SPIRV_DCL_ENCDEC
-
- SPIRVWord getRequiredSPIRVVersion() const override {
- switch (Kind) {
- case CapabilityNamedBarrier:
- case CapabilitySubgroupDispatch:
- case CapabilityPipeStorage:
- return SPIRV_1_1;
-
- default:
- return SPIRV_1_0;
- }
- }
-private:
- SPIRVCapabilityKind Kind;
-};
-
-template<class T>
-T* bcast(SPIRVEntry *E) {
- return static_cast<T*>(E);
-}
-
-template<spv::Op OC>
-bool isa(SPIRVEntry *E) {
- return E ? E->getOpCode() == OC : false;
-}
-
-// ToDo: The following typedef's are place holders for SPIRV entity classes
-// to be implemented.
-// Each time a new class is implemented, remove the corresponding typedef.
-// This is also an indication of how much work is left.
-#define _SPIRV_OP(x) typedef SPIRVEntryOpCodeOnly<Op##x> SPIRV##x;
-_SPIRV_OP(Nop)
-_SPIRV_OP(SourceContinued)
-_SPIRV_OP(TypeMatrix)
-_SPIRV_OP(TypeRuntimeArray)
-_SPIRV_OP(SpecConstantTrue)
-_SPIRV_OP(SpecConstantFalse)
-_SPIRV_OP(SpecConstant)
-_SPIRV_OP(SpecConstantComposite)
-_SPIRV_OP(Image)
-_SPIRV_OP(ImageTexelPointer)
-_SPIRV_OP(ImageSampleDrefImplicitLod)
-_SPIRV_OP(ImageSampleDrefExplicitLod)
-_SPIRV_OP(ImageSampleProjImplicitLod)
-_SPIRV_OP(ImageSampleProjExplicitLod)
-_SPIRV_OP(ImageSampleProjDrefImplicitLod)
-_SPIRV_OP(ImageSampleProjDrefExplicitLod)
-_SPIRV_OP(ImageFetch)
-_SPIRV_OP(ImageGather)
-_SPIRV_OP(ImageDrefGather)
-_SPIRV_OP(QuantizeToF16)
-_SPIRV_OP(Transpose)
-_SPIRV_OP(ArrayLength)
-_SPIRV_OP(SMod)
-_SPIRV_OP(MatrixTimesScalar)
-_SPIRV_OP(VectorTimesMatrix)
-_SPIRV_OP(MatrixTimesVector)
-_SPIRV_OP(MatrixTimesMatrix)
-_SPIRV_OP(OuterProduct)
-_SPIRV_OP(IAddCarry)
-_SPIRV_OP(ISubBorrow)
-_SPIRV_OP(SMulExtended)
-_SPIRV_OP(UMulExtended)
-_SPIRV_OP(BitFieldInsert)
-_SPIRV_OP(BitFieldSExtract)
-_SPIRV_OP(BitFieldUExtract)
-_SPIRV_OP(BitReverse)
-_SPIRV_OP(BitCount)
-_SPIRV_OP(DPdx)
-_SPIRV_OP(DPdy)
-_SPIRV_OP(Fwidth)
-_SPIRV_OP(DPdxFine)
-_SPIRV_OP(DPdyFine)
-_SPIRV_OP(FwidthFine)
-_SPIRV_OP(DPdxCoarse)
-_SPIRV_OP(DPdyCoarse)
-_SPIRV_OP(FwidthCoarse)
-_SPIRV_OP(EmitVertex)
-_SPIRV_OP(EndPrimitive)
-_SPIRV_OP(EmitStreamVertex)
-_SPIRV_OP(EndStreamPrimitive)
-_SPIRV_OP(Kill)
-_SPIRV_OP(ImageSparseSampleImplicitLod)
-_SPIRV_OP(ImageSparseSampleExplicitLod)
-_SPIRV_OP(ImageSparseSampleDrefImplicitLod)
-_SPIRV_OP(ImageSparseSampleDrefExplicitLod)
-_SPIRV_OP(ImageSparseSampleProjImplicitLod)
-_SPIRV_OP(ImageSparseSampleProjExplicitLod)
-_SPIRV_OP(ImageSparseSampleProjDrefImplicitLod)
-_SPIRV_OP(ImageSparseSampleProjDrefExplicitLod)
-_SPIRV_OP(ImageSparseFetch)
-_SPIRV_OP(ImageSparseGather)
-_SPIRV_OP(ImageSparseDrefGather)
-_SPIRV_OP(ImageSparseTexelsResident)
-_SPIRV_OP(NoLine)
-_SPIRV_OP(TypeNamedBarrier)
-_SPIRV_OP(NamedBarrierInitialize)
-_SPIRV_OP(MemoryNamedBarrier)
-_SPIRV_OP(GetKernelMaxNumSubgroups)
-_SPIRV_OP(GetKernelLocalSizeForSubgroupCount)
-_SPIRV_OP(SizeOf)
-#undef _SPIRV_OP
-
-}
-#endif /* SPIRVENTRY_HPP_ */
+//===- SPIRVEntry.h - Base Class for SPIR-V Entities -------------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines the base class for SPIRV entities. +/// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVENTRY_HPP_ +#define SPIRVENTRY_HPP_ + +#include "SPIRVEnum.h" +#include "SPIRVIsValidEnum.h" +#include "SPIRVError.h" +#include <cassert> +#include <iostream> +#include <map> +#include <memory> +#include <set> +#include <string> +#include <vector> + +namespace SPIRV{ + +class SPIRVModule; +class SPIRVEncoder; +class SPIRVDecoder; +class SPIRVType; +class SPIRVValue; +class SPIRVDecorate; +class SPIRVForward; +class SPIRVMemberDecorate; +class SPIRVLine; +class SPIRVString; +class SPIRVExtInst; + +// Add declaration of encode/decode functions to a class. +// Used inside class definition. +#define _SPIRV_DCL_ENCDEC \ + void encode(spv_ostream &O) const; \ + void decode(std::istream &I); + +#define _REQ_SPIRV_VER(Version) \ + SPIRVWord getRequiredSPIRVVersion() const override { return Version; } + +// Add implementation of encode/decode functions to a class. +// Used out side of class definition. +#define _SPIRV_IMP_ENCDEC0(Ty) \ + void Ty::encode(spv_ostream &O) const {} \ + void Ty::decode(std::istream &I) {} +#define _SPIRV_IMP_ENCDEC1(Ty,x) \ + void Ty::encode(spv_ostream &O) const { getEncoder(O) << x; } \ + void Ty::decode(std::istream &I) { getDecoder(I) >> x;} +#define _SPIRV_IMP_ENCDEC2(Ty,x,y) \ + void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y; } \ + void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y;} +#define _SPIRV_IMP_ENCDEC3(Ty,x,y,z) \ + void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z; } \ + void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z;} +#define _SPIRV_IMP_ENCDEC4(Ty,x,y,z,u) \ + void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z << \ + u; } \ + void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u;} +#define _SPIRV_IMP_ENCDEC5(Ty,x,y,z,u,v) \ + void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z << \ + u << v; } \ + void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v;} +#define _SPIRV_IMP_ENCDEC6(Ty,x,y,z,u,v,w) \ + void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z << \ + u << v << w; } \ + void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> \ + v >> w;} +#define _SPIRV_IMP_ENCDEC7(Ty,x,y,z,u,v,w,r) \ + void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z << \ + u << v << w << r; } \ + void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> \ + v >> w >> r;} +#define _SPIRV_IMP_ENCDEC8(Ty,x,y,z,u,v,w,r,s) \ + void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z << \ + u << v << w << r << s; } \ + void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> \ + v >> w >> r >> s;} +#define _SPIRV_IMP_ENCDEC9(Ty,x,y,z,u,v,w,r,s,t) \ + void Ty::encode(spv_ostream &O) const { getEncoder(O) << x << y << z << \ + u << v << w << r << s << t; } \ + void Ty::decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> \ + v >> w >> r >> s >> t;} + +// Add definition of encode/decode functions to a class. +// Used inside class definition. +#define _SPIRV_DEF_ENCDEC0 \ + void encode(spv_ostream &O) const {} \ + void decode(std::istream &I) {} +#define _SPIRV_DEF_ENCDEC1(x) \ + void encode(spv_ostream &O) const { getEncoder(O) << x; } \ + void decode(std::istream &I) { getDecoder(I) >> x;} +#define _SPIRV_DEF_ENCDEC2(x,y) \ + void encode(spv_ostream &O) const { getEncoder(O) << x << y; } \ + void decode(std::istream &I) { getDecoder(I) >> x >> y;} +#define _SPIRV_DEF_ENCDEC3(x,y,z) \ + void encode(spv_ostream &O) const { getEncoder(O) << x << y << z; } \ + void decode(std::istream &I) { getDecoder(I) >> x >> y >> z;} +#define _SPIRV_DEF_ENCDEC4(x,y,z,u) \ + void encode(spv_ostream &O) const { getEncoder(O) << x << y << z << u; } \ + void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u;} +#define _SPIRV_DEF_ENCDEC5(x,y,z,u,v) \ + void encode(spv_ostream &O) const { getEncoder(O) << x << y << z << u << \ + v; } \ + void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v;} +#define _SPIRV_DEF_ENCDEC6(x,y,z,u,v,w) \ + void encode(spv_ostream &O) const { getEncoder(O) << x << y << z << u << \ + v << w; } \ + void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> w;} +#define _SPIRV_DEF_ENCDEC7(x,y,z,u,v,w,r) \ + void encode(spv_ostream &O) const { getEncoder(O) << x << y << z << u << \ + v << w << r; } \ + void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> \ + w >> r;} +#define _SPIRV_DEF_ENCDEC8(x,y,z,u,v,w,r,s) \ + void encode(spv_ostream &O) const { getEncoder(O) << x << y << z << u << \ + v << w << r << s; } \ + void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> \ + w >> r >> s;} +#define _SPIRV_DEF_ENCDEC9(x,y,z,u,v,w,r,s,t) \ + void encode(spv_ostream &O) const { getEncoder(O) << x << y << z << u << \ + v << w << r << s << t; } \ + void decode(std::istream &I) { getDecoder(I) >> x >> y >> z >> u >> v >> \ + w >> r >> s >> t;} + +/// All SPIR-V in-memory-representation entities inherits from SPIRVEntry. +/// Usually there are two flavors of constructors of SPIRV objects: +/// +/// 1. complete constructor: It requires all the parameters needed to create a +/// SPIRV entity with complete information which can be validated. It is +/// usually used by LLVM/SPIR-V translator to create SPIRV object +/// corresponding to LLVM object. Such constructor calls validate() at +/// the end of the construction. +/// +/// 2. incomplete constructor: For leaf classes, it has no parameters. +/// It is usually called by SPIRVEntry::make(opcode) to create an incomplete +/// object which should not be validated. Then setWordCount(count) is +/// called to fix the size of the object if it is variable, and then the +/// information is filled by the virtual function decode(istream). +/// After that the object can be validated. +/// +/// To add a new SPIRV class: +/// +/// 1. It is recommended to name the class as SPIRVXXX if it has a fixed op code +/// OpXXX. Although it is not mandatory, doing this facilitates adding it to +/// the table of the factory function SPIRVEntry::create(). +/// 2. Inherit from proper SPIRV class such as SPIRVType, SPIRVValue, +/// SPIRVInstruction, etc. +/// 3. Implement virtual function encode(), decode(), validate(). +/// 4. If the object has variable size, implement virtual function +/// setWordCount(). +/// 5. If the class has special attributes, e.g. having no id, or having no +/// type as a value, set them in the constructors. +/// 6. If the class may represent SPIRV entity which has been added in version +/// later than 1.0, implement virtual function getRequiredSPIRVVersion(). +/// To automaticly update module's version you can also call protected +/// function updateModuleVersion() in the constructor. +/// 7. Add the class to the Table of SPIRVEntry::create(). +/// 8. Add the class to SPIRVToLLVM and LLVMToSPIRV. + +class SPIRVEntry { +public: + enum SPIRVEntryAttrib { + SPIRVEA_DEFAULT = 0, + SPIRVEA_NOID = 1, // Entry has no valid id + SPIRVEA_NOTYPE = 2, // Value has no type + }; + + // Complete constructor for objects with id + SPIRVEntry(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, + SPIRVId TheId) + :Module(M), OpCode(TheOpCode), Id(TheId), Attrib(SPIRVEA_DEFAULT), + WordCount(TheWordCount), Line(nullptr){ + validate(); + } + + // Complete constructor for objects without id + SPIRVEntry(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode) + :Module(M), OpCode(TheOpCode), Id(SPIRVID_INVALID), Attrib(SPIRVEA_NOID), + WordCount(TheWordCount), Line(nullptr){ + validate(); + } + + // Incomplete constructor + SPIRVEntry(Op TheOpCode) + :Module(NULL), OpCode(TheOpCode), Id(SPIRVID_INVALID), + Attrib(SPIRVEA_DEFAULT), WordCount(0), Line(nullptr){} + + SPIRVEntry() + :Module(NULL), OpCode(OpNop), Id(SPIRVID_INVALID), + Attrib(SPIRVEA_DEFAULT), WordCount(0), Line(nullptr){} + + + virtual ~SPIRVEntry(){} + + bool exist(SPIRVId)const; + template<class T> + T* get(SPIRVId TheId)const { return static_cast<T*>(getEntry(TheId));} + SPIRVEntry *getEntry(SPIRVId) const; + SPIRVEntry *getOrCreate(SPIRVId TheId) const; + SPIRVValue *getValue(SPIRVId TheId)const; + std::vector<SPIRVValue *> getValues(const std::vector<SPIRVId>&)const; + std::vector<SPIRVId> getIds(const std::vector<SPIRVValue *>)const; + SPIRVType *getValueType(SPIRVId TheId)const; + std::vector<SPIRVType *> getValueTypes(const std::vector<SPIRVId>&)const; + + virtual SPIRVDecoder getDecoder(std::istream &); + virtual SPIRVEncoder getEncoder(spv_ostream &)const; + SPIRVErrorLog &getErrorLog()const; + SPIRVId getId() const { assert(hasId()); return Id;} + std::shared_ptr<const SPIRVLine> getLine() const { return Line;} + SPIRVLinkageTypeKind getLinkageType() const; + Op getOpCode() const { return OpCode;} + SPIRVModule *getModule() const { return Module;} + virtual SPIRVCapVec getRequiredCapability() const { return SPIRVCapVec();} + const std::string& getName() const { return Name;} + bool hasDecorate(Decoration Kind, size_t Index = 0, + SPIRVWord *Result=0)const; + std::set<SPIRVWord> getDecorate(Decoration Kind, size_t Index = 0)const; + bool hasId() const { return !(Attrib & SPIRVEA_NOID);} + bool hasLine() const { return Line != nullptr;} + bool hasLinkageType() const; + bool isAtomic() const { return isAtomicOpCode(OpCode);} + bool isBasicBlock() const { return isLabel();} + bool isBuiltinCall() const { return OpCode == OpExtInst;} + bool isDecorate()const { return OpCode == OpDecorate;} + bool isMemberDecorate()const { return OpCode == OpMemberDecorate;} + bool isForward() const { return OpCode == OpForward;} + bool isLabel() const { return OpCode == OpLabel;} + bool isUndef() const { return OpCode == OpUndef;} + bool isControlBarrier() const { return OpCode == OpControlBarrier;} + bool isMemoryBarrier() const { return OpCode == OpMemoryBarrier;} + bool isVariable() const { return OpCode == OpVariable;} + bool isEndOfBlock() const; + virtual bool isInst() const { return false;} + virtual bool isOperandLiteral(unsigned Index) const { + assert(0 && "not implemented"); + return false; + } + + void addDecorate(SPIRVDecorate *); + void addDecorate(Decoration Kind); + void addDecorate(Decoration Kind, SPIRVWord Literal); + void eraseDecorate(Decoration); + void addMemberDecorate(SPIRVMemberDecorate *); + void addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind); + void addMemberDecorate(SPIRVWord MemberNumber, Decoration Kind, + SPIRVWord Literal); + void eraseMemberDecorate(SPIRVWord MemberNumber, Decoration Kind); + void setHasNoId() { Attrib |= SPIRVEA_NOID;} + void setId(SPIRVId TheId) { Id = TheId;} + void setLine(const std::shared_ptr<const SPIRVLine>& L); + void setLinkageType(SPIRVLinkageTypeKind); + void setModule(SPIRVModule *TheModule); + void setName(const std::string& TheName); + virtual void setScope(SPIRVEntry *Scope){}; + void takeAnnotations(SPIRVForward *); + void takeDecorates(SPIRVEntry *); + void takeMemberDecorates(SPIRVEntry *); + + /// After a SPIRV entry is created during reading SPIRV binary by default + /// constructor, this function is called to allow the SPIRV entry to resize + /// its variable sized member before decoding the remaining words. + virtual void setWordCount(SPIRVWord TheWordCount); + + /// Create an empty SPIRV object by op code, e.g. OpTypeInt creates + /// SPIRVTypeInt. + static SPIRVEntry *create(Op); + static std::unique_ptr<SPIRVEntry> create_unique(Op); + + /// Create an empty extended instruction. + static std::unique_ptr<SPIRVExtInst> create_unique( + SPIRVExtInstSetKind Set, + unsigned ExtOp); + + friend spv_ostream &operator<<(spv_ostream &O, const SPIRVEntry &E); + friend std::istream &operator>>(std::istream &I, SPIRVEntry &E); + virtual void encodeLine(spv_ostream &O) const; + virtual void encodeAll(spv_ostream &O) const; + virtual void encodeName(spv_ostream &O) const; + virtual void encodeChildren(spv_ostream &O)const; + virtual void encodeDecorate(spv_ostream &O)const; + virtual void encodeWordCountOpCode(spv_ostream &O)const; + virtual void encode(spv_ostream &O) const; + virtual void decode(std::istream &I); + + friend class SPIRVDecoder; + + /// Checks the integrity of the object. + virtual void validate()const { + assert(Module && "Invalid module"); + assert(OpCode != OpNop && "Invalid op code"); + assert((!hasId() || isValidId(Id)) && "Invalid Id"); + } + void validateFunctionControlMask(SPIRVWord FCtlMask)const; + void validateValues(const std::vector<SPIRVId> &)const; + void validateBuiltin(SPIRVWord, SPIRVWord)const; + + // By default assume SPIRV 1.0 as required version + virtual SPIRVWord getRequiredSPIRVVersion() const { return SPIRV_1_0; } + + virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { + return std::vector<SPIRVEntry*>(); + } + +protected: + /// An entry may have multiple FuncParamAttr decorations. + typedef std::multimap<Decoration, const SPIRVDecorate*> DecorateMapType; + typedef std::map<std::pair<SPIRVWord, Decoration>, + const SPIRVMemberDecorate*> MemberDecorateMapType; + + bool canHaveMemberDecorates() const { + return OpCode == OpTypeStruct || + OpCode == OpForward; + } + MemberDecorateMapType& getMemberDecorates() { + assert(canHaveMemberDecorates()); + return MemberDecorates; + } + + void updateModuleVersion() const; + + SPIRVModule *Module; + Op OpCode; + SPIRVId Id; + std::string Name; + unsigned Attrib; + SPIRVWord WordCount; + + DecorateMapType Decorates; + MemberDecorateMapType MemberDecorates; + std::shared_ptr<const SPIRVLine> Line; +}; + +class SPIRVEntryNoIdGeneric:public SPIRVEntry { +public: + SPIRVEntryNoIdGeneric(SPIRVModule *M, unsigned TheWordCount, Op OC) + :SPIRVEntry(M, TheWordCount, OC){ + setAttr(); + } + SPIRVEntryNoIdGeneric(Op OC):SPIRVEntry(OC){ + setAttr(); + } +protected: + void setAttr() { + setHasNoId(); + } +}; + +template<Op OC> +class SPIRVEntryNoId:public SPIRVEntryNoIdGeneric { +public: + SPIRVEntryNoId(SPIRVModule *M, unsigned TheWordCount) + :SPIRVEntryNoIdGeneric(M, TheWordCount, OC){} + SPIRVEntryNoId():SPIRVEntryNoIdGeneric(OC){} +}; + +template<Op TheOpCode> +class SPIRVEntryOpCodeOnly:public SPIRVEntryNoId<TheOpCode> { +public: + SPIRVEntryOpCodeOnly(){ + SPIRVEntry::WordCount = 1; + validate(); + } +protected: + _SPIRV_DEF_ENCDEC0 + void validate()const { + assert(isValidId(SPIRVEntry::OpCode)); + } +}; + +class SPIRVAnnotationGeneric:public SPIRVEntryNoIdGeneric { +public: + // Complete constructor + SPIRVAnnotationGeneric(SPIRVModule *TheModule, unsigned TheWordCount, Op OC, + SPIRVId TheTarget = SPIRVID_INVALID) + : SPIRVEntryNoIdGeneric(TheModule, TheWordCount, OC), Target(TheTarget) {} + // Incomplete constructor + SPIRVAnnotationGeneric(Op OC):SPIRVEntryNoIdGeneric(OC), + Target(SPIRVID_INVALID){} + + SPIRVId getTargetId()const { return Target;} + SPIRVForward *getOrCreateTarget()const; + void setTargetId(SPIRVId T) { Target = T;} +protected: + SPIRVId Target; +}; + +template<Op OC> +class SPIRVAnnotation:public SPIRVAnnotationGeneric { +public: + // Complete constructor + SPIRVAnnotation(const SPIRVEntry *TheTarget, unsigned TheWordCount) + : SPIRVAnnotationGeneric(TheTarget->getModule(), TheWordCount, OC, + TheTarget->getId()) {} + // Incomplete constructor + SPIRVAnnotation():SPIRVAnnotationGeneric(OC){} +}; + +class SPIRVEntryPoint:public SPIRVAnnotation<OpEntryPoint> { +public: + SPIRVEntryPoint(SPIRVModule *TheModule, SPIRVExecutionModelKind, + SPIRVId TheId, const std::string &TheName); + SPIRVEntryPoint():ExecModel(ExecutionModelKernel){} + _SPIRV_DCL_ENCDEC +protected: + SPIRVExecutionModelKind ExecModel; + std::string Name; +}; + + +class SPIRVName:public SPIRVAnnotation<OpName> { +public: + // Complete constructor + SPIRVName(const SPIRVEntry *TheTarget, const std::string& TheStr); + // Incomplete constructor + SPIRVName(){} +protected: + _SPIRV_DCL_ENCDEC + void validate() const; + + std::string Str; +}; + +class SPIRVMemberName:public SPIRVAnnotation<OpName> { +public: + static const SPIRVWord FixedWC = 3; + // Complete constructor + SPIRVMemberName(const SPIRVEntry *TheTarget, SPIRVWord TheMemberNumber, + const std::string& TheStr) + :SPIRVAnnotation(TheTarget, FixedWC + getSizeInWords(TheStr)), + MemberNumber(TheMemberNumber), Str(TheStr){ + validate(); + } + // Incomplete constructor + SPIRVMemberName():MemberNumber(SPIRVWORD_MAX){} +protected: + _SPIRV_DCL_ENCDEC + void validate() const; + SPIRVWord MemberNumber; + std::string Str; +}; + +class SPIRVString:public SPIRVEntry { + static const Op OC = OpString; + static const SPIRVWord FixedWC = 2; +public: + SPIRVString(SPIRVModule *M, SPIRVId TheId, const std::string &TheStr) + :SPIRVEntry(M, FixedWC + getSizeInWords(TheStr), OC, TheId), Str(TheStr){} + SPIRVString():SPIRVEntry(OC){} + _SPIRV_DCL_ENCDEC + const std::string &getStr()const { return Str;} +protected: + std::string Str; +}; + +class SPIRVLine: public SPIRVEntry { +public: + static const SPIRVWord WC = 4; + // Complete constructor + SPIRVLine(SPIRVModule *M, SPIRVId TheFileName, SPIRVWord TheLine, + SPIRVWord TheColumn) + :SPIRVEntry(M, WC, OpLine), + FileName(TheFileName), + Line(TheLine), + Column(TheColumn) { + Attrib = SPIRVEA_NOID | SPIRVEA_NOTYPE; + validate(); + } + // Incomplete constructor + SPIRVLine():SPIRVEntry(OpLine), FileName(SPIRVID_INVALID), Line(SPIRVWORD_MAX), + Column(SPIRVWORD_MAX) { + Attrib = SPIRVEA_NOID | SPIRVEA_NOTYPE; + } + + SPIRVWord getColumn() const { + return Column; + } + + void setColumn(const SPIRVWord column) { + Column = column; + } + + SPIRVId getFileName() const { + return FileName; + } + + const std::string &getFileNameStr() const { + return get<SPIRVString>(FileName)->getStr(); + } + + void setFileName(const SPIRVId fileName) { + FileName = fileName; + } + + SPIRVWord getLine() const { + return Line; + } + + void setLine(const SPIRVWord line) { + Line = line; + } + + bool operator!=(const SPIRVLine &O) const { + return !equals(O.FileName, O.Line, O.Column); + } + + bool equals(const SPIRVId TheFileName, + const SPIRVWord TheLine, + const SPIRVWord TheColumn) const { + return FileName == TheFileName && Line == TheLine && Column == TheColumn; + } + +protected: + _SPIRV_DCL_ENCDEC + void validate() const; + SPIRVId FileName; + SPIRVWord Line; + SPIRVWord Column; +}; + +class SPIRVExecutionMode:public SPIRVAnnotation<OpExecutionMode> { +public: + // Complete constructor for LocalSize, LocalSizeHint + SPIRVExecutionMode(SPIRVEntry *TheTarget, SPIRVExecutionModeKind TheExecMode, + SPIRVWord x, SPIRVWord y, SPIRVWord z) + :SPIRVAnnotation(TheTarget, 6), ExecMode(TheExecMode){ + WordLiterals.push_back(x); + WordLiterals.push_back(y); + WordLiterals.push_back(z); + updateModuleVersion(); + } + // Complete constructor for VecTypeHint, SubgroupSize, SubgroupsPerWorkgroup + SPIRVExecutionMode(SPIRVEntry *TheTarget, SPIRVExecutionModeKind TheExecMode, + SPIRVWord code) + :SPIRVAnnotation(TheTarget, 4), ExecMode(TheExecMode){ + WordLiterals.push_back(code); + updateModuleVersion(); + } + // Complete constructor for ContractionOff + SPIRVExecutionMode(SPIRVEntry *TheTarget, SPIRVExecutionModeKind TheExecMode) + :SPIRVAnnotation(TheTarget, 3), ExecMode(TheExecMode){ + updateModuleVersion(); + } + // Incomplete constructor + SPIRVExecutionMode():ExecMode(ExecutionModeInvocations){} + SPIRVExecutionModeKind getExecutionMode()const { return ExecMode;} + const std::vector<SPIRVWord>& getLiterals()const { return WordLiterals;} + SPIRVCapVec getRequiredCapability() const { + return getCapability(ExecMode); + } + + SPIRVWord getRequiredSPIRVVersion() const override { + switch (ExecMode) { + case ExecutionModeFinalizer: + case ExecutionModeInitializer: + case ExecutionModeSubgroupSize: + case ExecutionModeSubgroupsPerWorkgroup: + return SPIRV_1_1; + + default: + return SPIRV_1_0; + } + } + +protected: + _SPIRV_DCL_ENCDEC + SPIRVExecutionModeKind ExecMode; + std::vector<SPIRVWord> WordLiterals; +}; + + +class SPIRVComponentExecutionModes { + typedef std::map<SPIRVExecutionModeKind, SPIRVExecutionMode*> + SPIRVExecutionModeMap; +public: + void addExecutionMode(SPIRVExecutionMode *ExecMode) { + ExecModes[ExecMode->getExecutionMode()] = ExecMode; + } + SPIRVExecutionMode *getExecutionMode(SPIRVExecutionModeKind EMK)const { + auto Loc = ExecModes.find(EMK); + if (Loc == ExecModes.end()) + return nullptr; + return Loc->second; + } +protected: + SPIRVExecutionModeMap ExecModes; +}; + +class SPIRVExtInstImport:public SPIRVEntry { +public: + const static Op OC = OpExtInstImport; + // Complete constructor + SPIRVExtInstImport(SPIRVModule *TheModule, SPIRVId TheId, + const std::string& TheStr); + // Incomplete constructor + SPIRVExtInstImport():SPIRVEntry(OC){} +protected: + _SPIRV_DCL_ENCDEC + void validate() const; + + std::string Str; +}; + +class SPIRVMemoryModel:public SPIRVEntryNoId<OpMemoryModel> { +public: + SPIRVMemoryModel(SPIRVModule *M):SPIRVEntryNoId(M, 3){} + SPIRVMemoryModel(){} + _SPIRV_DCL_ENCDEC + void validate() const; +}; + +class SPIRVSource:public SPIRVEntryNoId<OpSource> { +public: + SPIRVSource(SPIRVModule *M):SPIRVEntryNoId(M, 3){} + SPIRVSource(){} + _SPIRV_DCL_ENCDEC +}; + +class SPIRVSourceExtension:public SPIRVEntryNoId<OpSourceExtension> { +public: + SPIRVSourceExtension(SPIRVModule *M, const std::string &SS); + SPIRVSourceExtension(){} + _SPIRV_DCL_ENCDEC +private: + std::string S; +}; + +class SPIRVExtension:public SPIRVEntryNoId<OpExtension> { +public: + SPIRVExtension(SPIRVModule *M, const std::string &SS); + SPIRVExtension(){} + _SPIRV_DCL_ENCDEC +private: + std::string S; +}; + +class SPIRVCapability:public SPIRVEntryNoId<OpCapability> { +public: + SPIRVCapability(SPIRVModule *M, SPIRVCapabilityKind K); + SPIRVCapability():Kind(CapabilityMatrix){} + _SPIRV_DCL_ENCDEC + + SPIRVWord getRequiredSPIRVVersion() const override { + switch (Kind) { + case CapabilityNamedBarrier: + case CapabilitySubgroupDispatch: + case CapabilityPipeStorage: + return SPIRV_1_1; + + default: + return SPIRV_1_0; + } + } +private: + SPIRVCapabilityKind Kind; +}; + +template<class T> +T* bcast(SPIRVEntry *E) { + return static_cast<T*>(E); +} + +template<spv::Op OC> +bool isa(SPIRVEntry *E) { + return E ? E->getOpCode() == OC : false; +} + +// ToDo: The following typedef's are place holders for SPIRV entity classes +// to be implemented. +// Each time a new class is implemented, remove the corresponding typedef. +// This is also an indication of how much work is left. +#define _SPIRV_OP(x) typedef SPIRVEntryOpCodeOnly<Op##x> SPIRV##x; +_SPIRV_OP(Nop) +_SPIRV_OP(SourceContinued) +_SPIRV_OP(TypeMatrix) +_SPIRV_OP(TypeRuntimeArray) +_SPIRV_OP(SpecConstantTrue) +_SPIRV_OP(SpecConstantFalse) +_SPIRV_OP(SpecConstant) +_SPIRV_OP(SpecConstantComposite) +_SPIRV_OP(Image) +_SPIRV_OP(ImageTexelPointer) +_SPIRV_OP(ImageSampleDrefImplicitLod) +_SPIRV_OP(ImageSampleDrefExplicitLod) +_SPIRV_OP(ImageSampleProjImplicitLod) +_SPIRV_OP(ImageSampleProjExplicitLod) +_SPIRV_OP(ImageSampleProjDrefImplicitLod) +_SPIRV_OP(ImageSampleProjDrefExplicitLod) +_SPIRV_OP(ImageFetch) +_SPIRV_OP(ImageGather) +_SPIRV_OP(ImageDrefGather) +_SPIRV_OP(QuantizeToF16) +_SPIRV_OP(Transpose) +_SPIRV_OP(ArrayLength) +_SPIRV_OP(SMod) +_SPIRV_OP(MatrixTimesScalar) +_SPIRV_OP(VectorTimesMatrix) +_SPIRV_OP(MatrixTimesVector) +_SPIRV_OP(MatrixTimesMatrix) +_SPIRV_OP(OuterProduct) +_SPIRV_OP(IAddCarry) +_SPIRV_OP(ISubBorrow) +_SPIRV_OP(SMulExtended) +_SPIRV_OP(UMulExtended) +_SPIRV_OP(BitFieldInsert) +_SPIRV_OP(BitFieldSExtract) +_SPIRV_OP(BitFieldUExtract) +_SPIRV_OP(BitReverse) +_SPIRV_OP(BitCount) +_SPIRV_OP(DPdx) +_SPIRV_OP(DPdy) +_SPIRV_OP(Fwidth) +_SPIRV_OP(DPdxFine) +_SPIRV_OP(DPdyFine) +_SPIRV_OP(FwidthFine) +_SPIRV_OP(DPdxCoarse) +_SPIRV_OP(DPdyCoarse) +_SPIRV_OP(FwidthCoarse) +_SPIRV_OP(EmitVertex) +_SPIRV_OP(EndPrimitive) +_SPIRV_OP(EmitStreamVertex) +_SPIRV_OP(EndStreamPrimitive) +_SPIRV_OP(Kill) +_SPIRV_OP(ImageSparseSampleImplicitLod) +_SPIRV_OP(ImageSparseSampleExplicitLod) +_SPIRV_OP(ImageSparseSampleDrefImplicitLod) +_SPIRV_OP(ImageSparseSampleDrefExplicitLod) +_SPIRV_OP(ImageSparseSampleProjImplicitLod) +_SPIRV_OP(ImageSparseSampleProjExplicitLod) +_SPIRV_OP(ImageSparseSampleProjDrefImplicitLod) +_SPIRV_OP(ImageSparseSampleProjDrefExplicitLod) +_SPIRV_OP(ImageSparseFetch) +_SPIRV_OP(ImageSparseGather) +_SPIRV_OP(ImageSparseDrefGather) +_SPIRV_OP(ImageSparseTexelsResident) +_SPIRV_OP(NoLine) +_SPIRV_OP(TypeNamedBarrier) +_SPIRV_OP(NamedBarrierInitialize) +_SPIRV_OP(MemoryNamedBarrier) +_SPIRV_OP(GetKernelMaxNumSubgroups) +_SPIRV_OP(GetKernelLocalSizeForSubgroupCount) +_SPIRV_OP(SizeOf) +#undef _SPIRV_OP + +} +#endif /* SPIRVENTRY_HPP_ */ diff --git a/lib/SPIRV/libSPIRV/SPIRVEnum.h b/lib/SPIRV/libSPIRV/SPIRVEnum.h index 3cbff32..77e269e 100644 --- a/lib/SPIRV/libSPIRV/SPIRVEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVEnum.h @@ -1,418 +1,418 @@ -//===- SPIRVEnum.h - SPIR-V enums -------------------------------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines SPIR-V enums.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVENUM_HPP_
-#define SPIRVENUM_HPP_
-
-#include "spirv.hpp"
-#include "SPIRVOpCode.h"
-#include <cstdint>
-using namespace spv;
-
-namespace SPIRV{
-
-typedef uint32_t SPIRVWord;
-typedef uint32_t SPIRVId;
-#define SPIRVID_MAX ~0U
-#define SPIRVID_INVALID ~0U
-#define SPIRVWORD_MAX ~0U
-
-inline bool
-isValidId(SPIRVId Id) { return Id != SPIRVID_INVALID && Id != 0;}
-
-inline SPIRVWord
-mkWord(unsigned WordCount, Op OpCode) {
- return (WordCount << 16) | OpCode;
-}
-
-const static unsigned kSPIRVMemOrderSemanticMask = 0x1F;
-
-enum SPIRVVersion : SPIRVWord {
- SPIRV_1_0 = 0x00010000,
- SPIRV_1_1 = 0x00010100
-};
-
-enum SPIRVGeneratorKind {
- SPIRVGEN_KhronosLLVMSPIRVTranslator = 6,
- SPIRVGEN_KhronosSPIRVAssembler = 7,
-};
-
-enum SPIRVInstructionSchemaKind {
- SPIRVISCH_Default,
-};
-
-enum SPIRVExtInstSetKind {
- SPIRVEIS_OpenCL,
- SPIRVEIS_Count,
-};
-
-enum SPIRVSamplerAddressingModeKind {
- SPIRVSAM_None = 0,
- SPIRVSAM_ClampEdge = 2,
- SPIRVSAM_Clamp = 4,
- SPIRVSAM_Repeat = 6,
- SPIRVSAM_RepeatMirrored = 8,
- SPIRVSAM_Invalid = 255,
-};
-
-enum SPIRVSamplerFilterModeKind {
- SPIRVSFM_Nearest = 16,
- SPIRVSFM_Linear = 32,
- SPIRVSFM_Invalid = 255,
-};
-
-typedef spv::Capability SPIRVCapabilityKind;
-typedef spv::ExecutionModel SPIRVExecutionModelKind;
-typedef spv::ExecutionMode SPIRVExecutionModeKind;
-typedef spv::AccessQualifier SPIRVAccessQualifierKind;
-typedef spv::AddressingModel SPIRVAddressingModelKind;
-typedef spv::LinkageType SPIRVLinkageTypeKind;
-typedef spv::MemoryModel SPIRVMemoryModelKind;
-typedef spv::StorageClass SPIRVStorageClassKind;
-typedef spv::FunctionControlMask SPIRVFunctionControlMaskKind;
-typedef spv::FPRoundingMode SPIRVFPRoundingModeKind;
-typedef spv::FunctionParameterAttribute SPIRVFuncParamAttrKind;
-typedef spv::BuiltIn SPIRVBuiltinVariableKind;
-typedef spv::MemoryAccessMask SPIRVMemoryAccessKind;
-typedef spv::GroupOperation SPIRVGroupOperationKind;
-typedef spv::Dim SPIRVImageDimKind;
-typedef std::vector<SPIRVCapabilityKind> SPIRVCapVec;
-
-template<> inline void
-SPIRVMap<SPIRVExtInstSetKind, std::string>::init() {
- add(SPIRVEIS_OpenCL, "OpenCL.std");
-}
-typedef SPIRVMap<SPIRVExtInstSetKind, std::string> SPIRVBuiltinSetNameMap;
-
-template<typename K>
-SPIRVCapVec
-getCapability(K Key) {
- SPIRVCapVec V;
- SPIRVMap<K, SPIRVCapVec>::find(Key, &V);
- return std::move(V);
-}
-
-#define ADD_VEC_INIT(Cap, ...) \
-{ \
- SPIRVCapabilityKind C[] = __VA_ARGS__; \
- SPIRVCapVec V(C, C + sizeof(C) / sizeof(C[0])); \
- add(Cap, V); \
-}
-
-template<> inline void
-SPIRVMap<SPIRVCapabilityKind, SPIRVCapVec>::init() {
- ADD_VEC_INIT(CapabilityShader, { CapabilityMatrix });
- ADD_VEC_INIT(CapabilityGeometry, { CapabilityShader });
- ADD_VEC_INIT(CapabilityTessellation, { CapabilityShader });
- ADD_VEC_INIT(CapabilityVector16, { CapabilityKernel });
- ADD_VEC_INIT(CapabilityFloat16Buffer, { CapabilityKernel });
- ADD_VEC_INIT(CapabilityInt64Atomics, { CapabilityInt64 });
- ADD_VEC_INIT(CapabilityImageBasic, { CapabilityKernel });
- ADD_VEC_INIT(CapabilityImageReadWrite, { CapabilityImageBasic });
- ADD_VEC_INIT(CapabilityImageMipmap, { CapabilityImageBasic });
- ADD_VEC_INIT(CapabilityPipes, { CapabilityKernel });
- ADD_VEC_INIT(CapabilityDeviceEnqueue, { CapabilityKernel });
- ADD_VEC_INIT(CapabilityLiteralSampler, { CapabilityKernel });
- ADD_VEC_INIT(CapabilityAtomicStorage, { CapabilityShader });
- ADD_VEC_INIT(CapabilityTessellationPointSize, { CapabilityTessellation });
- ADD_VEC_INIT(CapabilityGeometryPointSize, { CapabilityGeometry });
- ADD_VEC_INIT(CapabilityImageGatherExtended, { CapabilityShader });
- ADD_VEC_INIT(CapabilityStorageImageMultisample, { CapabilityShader });
- ADD_VEC_INIT(CapabilityUniformBufferArrayDynamicIndexing, { CapabilityShader });
- ADD_VEC_INIT(CapabilitySampledImageArrayDynamicIndexing, { CapabilityShader });
- ADD_VEC_INIT(CapabilityStorageBufferArrayDynamicIndexing, { CapabilityShader });
- ADD_VEC_INIT(CapabilityStorageImageArrayDynamicIndexing, { CapabilityShader });
- ADD_VEC_INIT(CapabilityClipDistance, { CapabilityShader });
- ADD_VEC_INIT(CapabilityCullDistance, { CapabilityShader });
- ADD_VEC_INIT(CapabilityImageCubeArray, { CapabilitySampledCubeArray });
- ADD_VEC_INIT(CapabilitySampleRateShading, { CapabilityShader });
- ADD_VEC_INIT(CapabilityImageRect, { CapabilitySampledRect });
- ADD_VEC_INIT(CapabilitySampledRect, { CapabilityShader });
- ADD_VEC_INIT(CapabilityGenericPointer, { CapabilityAddresses });
- ADD_VEC_INIT(CapabilityInt8, { CapabilityKernel });
- ADD_VEC_INIT(CapabilityInputAttachment, { CapabilityShader });
- ADD_VEC_INIT(CapabilitySparseResidency, { CapabilityShader });
- ADD_VEC_INIT(CapabilityMinLod, { CapabilityShader });
- ADD_VEC_INIT(CapabilityImage1D, { CapabilitySampled1D });
- ADD_VEC_INIT(CapabilitySampledCubeArray, { CapabilityShader });
- ADD_VEC_INIT(CapabilityImageBuffer, { CapabilitySampledBuffer });
- ADD_VEC_INIT(CapabilityImageMSArray, { CapabilityShader });
- ADD_VEC_INIT(CapabilityStorageImageExtendedFormats, { CapabilityShader });
- ADD_VEC_INIT(CapabilityImageQuery, { CapabilityShader });
- ADD_VEC_INIT(CapabilityDerivativeControl, { CapabilityShader });
- ADD_VEC_INIT(CapabilityInterpolationFunction, { CapabilityShader });
- ADD_VEC_INIT(CapabilityTransformFeedback, { CapabilityShader });
- ADD_VEC_INIT(CapabilityGeometryStreams, { CapabilityGeometry });
- ADD_VEC_INIT(CapabilityStorageImageReadWithoutFormat, { CapabilityShader });
- ADD_VEC_INIT(CapabilityStorageImageWriteWithoutFormat, { CapabilityShader });
- ADD_VEC_INIT(CapabilityMultiViewport, { CapabilityGeometry });
-}
-
-template<> inline void
-SPIRVMap<SPIRVExecutionModelKind, SPIRVCapVec>::init() {
- ADD_VEC_INIT(ExecutionModelVertex, { CapabilityShader });
- ADD_VEC_INIT(ExecutionModelTessellationControl, { CapabilityTessellation });
- ADD_VEC_INIT(ExecutionModelTessellationEvaluation, { CapabilityTessellation });
- ADD_VEC_INIT(ExecutionModelGeometry, { CapabilityGeometry });
- ADD_VEC_INIT(ExecutionModelFragment, { CapabilityShader });
- ADD_VEC_INIT(ExecutionModelGLCompute, { CapabilityShader });
- ADD_VEC_INIT(ExecutionModelKernel, { CapabilityKernel });
-}
-
-template<> inline void
-SPIRVMap<SPIRVExecutionModeKind, SPIRVCapVec>::init() {
- ADD_VEC_INIT(ExecutionModeInvocations, { CapabilityGeometry });
- ADD_VEC_INIT(ExecutionModeSpacingEqual, { CapabilityTessellation });
- ADD_VEC_INIT(ExecutionModeSpacingFractionalEven, { CapabilityTessellation });
- ADD_VEC_INIT(ExecutionModeSpacingFractionalOdd, { CapabilityTessellation });
- ADD_VEC_INIT(ExecutionModeVertexOrderCw, { CapabilityTessellation });
- ADD_VEC_INIT(ExecutionModeVertexOrderCcw, { CapabilityTessellation });
- ADD_VEC_INIT(ExecutionModePixelCenterInteger, { CapabilityShader });
- ADD_VEC_INIT(ExecutionModeOriginUpperLeft, { CapabilityShader });
- ADD_VEC_INIT(ExecutionModeOriginLowerLeft, { CapabilityShader });
- ADD_VEC_INIT(ExecutionModeEarlyFragmentTests, { CapabilityShader });
- ADD_VEC_INIT(ExecutionModePointMode, { CapabilityTessellation });
- ADD_VEC_INIT(ExecutionModeXfb, { CapabilityTransformFeedback });
- ADD_VEC_INIT(ExecutionModeDepthReplacing, { CapabilityShader });
- ADD_VEC_INIT(ExecutionModeDepthGreater, { CapabilityShader });
- ADD_VEC_INIT(ExecutionModeDepthLess, { CapabilityShader });
- ADD_VEC_INIT(ExecutionModeDepthUnchanged, { CapabilityShader });
- ADD_VEC_INIT(ExecutionModeLocalSizeHint, { CapabilityKernel });
- ADD_VEC_INIT(ExecutionModeInputPoints, { CapabilityGeometry });
- ADD_VEC_INIT(ExecutionModeInputLines, { CapabilityGeometry });
- ADD_VEC_INIT(ExecutionModeInputLinesAdjacency, { CapabilityGeometry });
- ADD_VEC_INIT(ExecutionModeTriangles, { CapabilityGeometry, CapabilityTessellation });
- ADD_VEC_INIT(ExecutionModeInputTrianglesAdjacency, { CapabilityGeometry });
- ADD_VEC_INIT(ExecutionModeQuads, { CapabilityTessellation });
- ADD_VEC_INIT(ExecutionModeIsolines, { CapabilityTessellation });
- ADD_VEC_INIT(ExecutionModeOutputVertices, { CapabilityGeometry, CapabilityTessellation });
- ADD_VEC_INIT(ExecutionModeOutputPoints, { CapabilityGeometry });
- ADD_VEC_INIT(ExecutionModeOutputLineStrip, { CapabilityGeometry });
- ADD_VEC_INIT(ExecutionModeOutputTriangleStrip, { CapabilityGeometry });
- ADD_VEC_INIT(ExecutionModeVecTypeHint, { CapabilityKernel });
- ADD_VEC_INIT(ExecutionModeContractionOff, { CapabilityKernel });
-}
-
-template<> inline void
-SPIRVMap<SPIRVMemoryModelKind, SPIRVCapVec>::init() {
- ADD_VEC_INIT(MemoryModelSimple, { CapabilityShader });
- ADD_VEC_INIT(MemoryModelGLSL450, { CapabilityShader });
- ADD_VEC_INIT(MemoryModelOpenCL, { CapabilityKernel });
-}
-
-template<> inline void
-SPIRVMap<SPIRVStorageClassKind, SPIRVCapVec>::init() {
- ADD_VEC_INIT(StorageClassInput, { CapabilityShader });
- ADD_VEC_INIT(StorageClassUniform, { CapabilityShader });
- ADD_VEC_INIT(StorageClassOutput, { CapabilityShader });
- ADD_VEC_INIT(StorageClassPrivate, { CapabilityShader });
- ADD_VEC_INIT(StorageClassGeneric, { CapabilityGenericPointer });
- ADD_VEC_INIT(StorageClassPushConstant, { CapabilityShader });
- ADD_VEC_INIT(StorageClassAtomicCounter, { CapabilityAtomicStorage });
-}
-
-template<> inline void
-SPIRVMap<SPIRVImageDimKind, SPIRVCapVec>::init() {
- ADD_VEC_INIT(Dim1D, { CapabilitySampled1D });
- ADD_VEC_INIT(DimCube, { CapabilityShader });
- ADD_VEC_INIT(DimRect, { CapabilitySampledRect });
- ADD_VEC_INIT(DimBuffer, { CapabilitySampledBuffer });
- ADD_VEC_INIT(DimSubpassData, {CapabilityInputAttachment });
-}
-
-template<> inline void
-SPIRVMap<ImageFormat, SPIRVCapVec>::init() {
- ADD_VEC_INIT(ImageFormatRgba32f, { CapabilityShader });
- ADD_VEC_INIT(ImageFormatRgba16f, { CapabilityShader });
- ADD_VEC_INIT(ImageFormatR32f, { CapabilityShader });
- ADD_VEC_INIT(ImageFormatRgba8, { CapabilityShader });
- ADD_VEC_INIT(ImageFormatRgba8Snorm, { CapabilityShader });
- ADD_VEC_INIT(ImageFormatRg32f, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRg16f, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatR11fG11fB10f, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatR16f, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRgba16, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRgb10A2, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRg16, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRg8, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatR16, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatR8, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRgba16Snorm, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRg16Snorm, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRg8Snorm, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatR16Snorm, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatR8Snorm, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRgba32i, { CapabilityShader });
- ADD_VEC_INIT(ImageFormatRgba16i, { CapabilityShader });
- ADD_VEC_INIT(ImageFormatRgba8i, { CapabilityShader });
- ADD_VEC_INIT(ImageFormatR32i, { CapabilityShader });
- ADD_VEC_INIT(ImageFormatRg32i, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRg16i, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRg8i, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatR16i, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatR8i, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRgba32ui, { CapabilityShader });
- ADD_VEC_INIT(ImageFormatRgba16ui, { CapabilityShader });
- ADD_VEC_INIT(ImageFormatRgba8ui, { CapabilityShader });
- ADD_VEC_INIT(ImageFormatR32ui, { CapabilityShader });
- ADD_VEC_INIT(ImageFormatRgb10a2ui, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRg32ui, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatRg16ui, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatR16ui, { CapabilityStorageImageExtendedFormats });
- ADD_VEC_INIT(ImageFormatR8ui, { CapabilityStorageImageExtendedFormats });
-}
-
-template<> inline void
-SPIRVMap<ImageOperandsMask, SPIRVCapVec>::init() {
- ADD_VEC_INIT(ImageOperandsBiasMask, { CapabilityShader });
- ADD_VEC_INIT(ImageOperandsOffsetMask, { CapabilityImageGatherExtended });
- ADD_VEC_INIT(ImageOperandsMinLodMask, { CapabilityMinLod });
-}
-
-template<> inline void
-SPIRVMap<Decoration, SPIRVCapVec>::init() {
- ADD_VEC_INIT(DecorationRelaxedPrecision, { CapabilityShader });
- ADD_VEC_INIT(DecorationSpecId, { CapabilityShader });
- ADD_VEC_INIT(DecorationBlock, { CapabilityShader });
- ADD_VEC_INIT(DecorationBufferBlock, { CapabilityShader });
- ADD_VEC_INIT(DecorationRowMajor, { CapabilityMatrix });
- ADD_VEC_INIT(DecorationColMajor, { CapabilityMatrix });
- ADD_VEC_INIT(DecorationArrayStride, { CapabilityShader });
- ADD_VEC_INIT(DecorationMatrixStride, { CapabilityMatrix });
- ADD_VEC_INIT(DecorationGLSLShared, { CapabilityShader });
- ADD_VEC_INIT(DecorationGLSLPacked, { CapabilityShader });
- ADD_VEC_INIT(DecorationCPacked, { CapabilityKernel });
- ADD_VEC_INIT(DecorationNoPerspective, { CapabilityShader });
- ADD_VEC_INIT(DecorationFlat, { CapabilityShader });
- ADD_VEC_INIT(DecorationPatch, { CapabilityTessellation });
- ADD_VEC_INIT(DecorationCentroid, { CapabilityShader });
- ADD_VEC_INIT(DecorationSample, { CapabilitySampleRateShading });
- ADD_VEC_INIT(DecorationInvariant, { CapabilityShader });
- ADD_VEC_INIT(DecorationConstant, { CapabilityKernel });
- ADD_VEC_INIT(DecorationUniform, { CapabilityShader });
- ADD_VEC_INIT(DecorationSaturatedConversion, { CapabilityKernel });
- ADD_VEC_INIT(DecorationStream, { CapabilityGeometryStreams });
- ADD_VEC_INIT(DecorationLocation, { CapabilityShader });
- ADD_VEC_INIT(DecorationComponent, { CapabilityShader });
- ADD_VEC_INIT(DecorationIndex, { CapabilityShader });
- ADD_VEC_INIT(DecorationBinding, { CapabilityShader });
- ADD_VEC_INIT(DecorationDescriptorSet, { CapabilityShader });
- ADD_VEC_INIT(DecorationOffset, { CapabilityShader });
- ADD_VEC_INIT(DecorationXfbBuffer, { CapabilityTransformFeedback });
- ADD_VEC_INIT(DecorationXfbStride, { CapabilityTransformFeedback });
- ADD_VEC_INIT(DecorationFuncParamAttr, { CapabilityKernel });
- ADD_VEC_INIT(DecorationFPRoundingMode, { CapabilityKernel });
- ADD_VEC_INIT(DecorationFPFastMathMode, { CapabilityKernel });
- ADD_VEC_INIT(DecorationLinkageAttributes, { CapabilityLinkage });
- ADD_VEC_INIT(DecorationNoContraction, { CapabilityShader });
- ADD_VEC_INIT(DecorationInputAttachmentIndex, { CapabilityInputAttachment });
- ADD_VEC_INIT(DecorationAlignment, { CapabilityKernel });
-}
-
-template<> inline void
-SPIRVMap<BuiltIn, SPIRVCapVec>::init() {
- ADD_VEC_INIT(BuiltInPosition, { CapabilityShader });
- ADD_VEC_INIT(BuiltInPointSize, { CapabilityShader });
- ADD_VEC_INIT(BuiltInClipDistance, { CapabilityClipDistance });
- ADD_VEC_INIT(BuiltInCullDistance, { CapabilityCullDistance });
- ADD_VEC_INIT(BuiltInVertexId, { CapabilityShader });
- ADD_VEC_INIT(BuiltInInstanceId, { CapabilityShader });
- ADD_VEC_INIT(BuiltInPrimitiveId, { CapabilityGeometry, CapabilityTessellation });
- ADD_VEC_INIT(BuiltInInvocationId, { CapabilityGeometry, CapabilityTessellation });
- ADD_VEC_INIT(BuiltInLayer, { CapabilityGeometry });
- ADD_VEC_INIT(BuiltInViewportIndex, { CapabilityMultiViewport });
- ADD_VEC_INIT(BuiltInTessLevelOuter, { CapabilityTessellation });
- ADD_VEC_INIT(BuiltInTessLevelInner, { CapabilityTessellation });
- ADD_VEC_INIT(BuiltInTessCoord, { CapabilityTessellation });
- ADD_VEC_INIT(BuiltInPatchVertices, { CapabilityTessellation });
- ADD_VEC_INIT(BuiltInFragCoord, { CapabilityShader });
- ADD_VEC_INIT(BuiltInPointCoord, { CapabilityShader });
- ADD_VEC_INIT(BuiltInFrontFacing, { CapabilityShader });
- ADD_VEC_INIT(BuiltInSampleId, { CapabilitySampleRateShading });
- ADD_VEC_INIT(BuiltInSamplePosition, { CapabilitySampleRateShading });
- ADD_VEC_INIT(BuiltInSampleMask, { CapabilitySampleRateShading });
- ADD_VEC_INIT(BuiltInFragDepth, { CapabilityShader });
- ADD_VEC_INIT(BuiltInHelperInvocation, { CapabilityShader });
- ADD_VEC_INIT(BuiltInWorkDim, { CapabilityKernel });
- ADD_VEC_INIT(BuiltInGlobalSize, { CapabilityKernel });
- ADD_VEC_INIT(BuiltInEnqueuedWorkgroupSize, { CapabilityKernel });
- ADD_VEC_INIT(BuiltInGlobalOffset, { CapabilityKernel });
- ADD_VEC_INIT(BuiltInGlobalLinearId, { CapabilityKernel });
- ADD_VEC_INIT(BuiltInSubgroupSize, { CapabilityKernel });
- ADD_VEC_INIT(BuiltInSubgroupMaxSize, { CapabilityKernel });
- ADD_VEC_INIT(BuiltInNumSubgroups, { CapabilityKernel });
- ADD_VEC_INIT(BuiltInNumEnqueuedSubgroups, { CapabilityKernel });
- ADD_VEC_INIT(BuiltInSubgroupId, { CapabilityKernel });
- ADD_VEC_INIT(BuiltInSubgroupLocalInvocationId, { CapabilityKernel });
- ADD_VEC_INIT(BuiltInVertexIndex, { CapabilityShader });
- ADD_VEC_INIT(BuiltInInstanceIndex, { CapabilityShader });
-}
-
-template<> inline void
-SPIRVMap<MemorySemanticsMask, SPIRVCapVec>::init() {
- ADD_VEC_INIT(MemorySemanticsUniformMemoryMask, { CapabilityShader });
- ADD_VEC_INIT(MemorySemanticsAtomicCounterMemoryMask, { CapabilityAtomicStorage });
-}
-
-#undef ADD_VEC_INIT
-
-inline unsigned
-getImageDimension(SPIRVImageDimKind K) {
- switch(K){
- case Dim1D: return 1;
- case Dim2D: return 2;
- case Dim3D: return 3;
- case DimCube: return 2;
- case DimRect: return 2;
- case DimBuffer: return 1;
- default: return 0;
- }
-}
-
-/// Extract memory order part of SPIR-V memory semantics.
-inline unsigned
-extractSPIRVMemOrderSemantic(unsigned Sema) {
- return Sema & kSPIRVMemOrderSemanticMask;
-}
-
-
-}
-
-
-#endif /* SPIRVENUM_HPP_ */
+//===- SPIRVEnum.h - SPIR-V enums -------------------------------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines SPIR-V enums. +/// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVENUM_HPP_ +#define SPIRVENUM_HPP_ + +#include "spirv.hpp" +#include "SPIRVOpCode.h" +#include <cstdint> +using namespace spv; + +namespace SPIRV{ + +typedef uint32_t SPIRVWord; +typedef uint32_t SPIRVId; +#define SPIRVID_MAX ~0U +#define SPIRVID_INVALID ~0U +#define SPIRVWORD_MAX ~0U + +inline bool +isValidId(SPIRVId Id) { return Id != SPIRVID_INVALID && Id != 0;} + +inline SPIRVWord +mkWord(unsigned WordCount, Op OpCode) { + return (WordCount << 16) | OpCode; +} + +const static unsigned kSPIRVMemOrderSemanticMask = 0x1F; + +enum SPIRVVersion : SPIRVWord { + SPIRV_1_0 = 0x00010000, + SPIRV_1_1 = 0x00010100 +}; + +enum SPIRVGeneratorKind { + SPIRVGEN_KhronosLLVMSPIRVTranslator = 6, + SPIRVGEN_KhronosSPIRVAssembler = 7, +}; + +enum SPIRVInstructionSchemaKind { + SPIRVISCH_Default, +}; + +enum SPIRVExtInstSetKind { + SPIRVEIS_OpenCL, + SPIRVEIS_Count, +}; + +enum SPIRVSamplerAddressingModeKind { + SPIRVSAM_None = 0, + SPIRVSAM_ClampEdge = 2, + SPIRVSAM_Clamp = 4, + SPIRVSAM_Repeat = 6, + SPIRVSAM_RepeatMirrored = 8, + SPIRVSAM_Invalid = 255, +}; + +enum SPIRVSamplerFilterModeKind { + SPIRVSFM_Nearest = 16, + SPIRVSFM_Linear = 32, + SPIRVSFM_Invalid = 255, +}; + +typedef spv::Capability SPIRVCapabilityKind; +typedef spv::ExecutionModel SPIRVExecutionModelKind; +typedef spv::ExecutionMode SPIRVExecutionModeKind; +typedef spv::AccessQualifier SPIRVAccessQualifierKind; +typedef spv::AddressingModel SPIRVAddressingModelKind; +typedef spv::LinkageType SPIRVLinkageTypeKind; +typedef spv::MemoryModel SPIRVMemoryModelKind; +typedef spv::StorageClass SPIRVStorageClassKind; +typedef spv::FunctionControlMask SPIRVFunctionControlMaskKind; +typedef spv::FPRoundingMode SPIRVFPRoundingModeKind; +typedef spv::FunctionParameterAttribute SPIRVFuncParamAttrKind; +typedef spv::BuiltIn SPIRVBuiltinVariableKind; +typedef spv::MemoryAccessMask SPIRVMemoryAccessKind; +typedef spv::GroupOperation SPIRVGroupOperationKind; +typedef spv::Dim SPIRVImageDimKind; +typedef std::vector<SPIRVCapabilityKind> SPIRVCapVec; + +template<> inline void +SPIRVMap<SPIRVExtInstSetKind, std::string>::init() { + add(SPIRVEIS_OpenCL, "OpenCL.std"); +} +typedef SPIRVMap<SPIRVExtInstSetKind, std::string> SPIRVBuiltinSetNameMap; + +template<typename K> +SPIRVCapVec +getCapability(K Key) { + SPIRVCapVec V; + SPIRVMap<K, SPIRVCapVec>::find(Key, &V); + return std::move(V); +} + +#define ADD_VEC_INIT(Cap, ...) \ +{ \ + SPIRVCapabilityKind C[] = __VA_ARGS__; \ + SPIRVCapVec V(C, C + sizeof(C) / sizeof(C[0])); \ + add(Cap, V); \ +} + +template<> inline void +SPIRVMap<SPIRVCapabilityKind, SPIRVCapVec>::init() { + ADD_VEC_INIT(CapabilityShader, { CapabilityMatrix }); + ADD_VEC_INIT(CapabilityGeometry, { CapabilityShader }); + ADD_VEC_INIT(CapabilityTessellation, { CapabilityShader }); + ADD_VEC_INIT(CapabilityVector16, { CapabilityKernel }); + ADD_VEC_INIT(CapabilityFloat16Buffer, { CapabilityKernel }); + ADD_VEC_INIT(CapabilityInt64Atomics, { CapabilityInt64 }); + ADD_VEC_INIT(CapabilityImageBasic, { CapabilityKernel }); + ADD_VEC_INIT(CapabilityImageReadWrite, { CapabilityImageBasic }); + ADD_VEC_INIT(CapabilityImageMipmap, { CapabilityImageBasic }); + ADD_VEC_INIT(CapabilityPipes, { CapabilityKernel }); + ADD_VEC_INIT(CapabilityDeviceEnqueue, { CapabilityKernel }); + ADD_VEC_INIT(CapabilityLiteralSampler, { CapabilityKernel }); + ADD_VEC_INIT(CapabilityAtomicStorage, { CapabilityShader }); + ADD_VEC_INIT(CapabilityTessellationPointSize, { CapabilityTessellation }); + ADD_VEC_INIT(CapabilityGeometryPointSize, { CapabilityGeometry }); + ADD_VEC_INIT(CapabilityImageGatherExtended, { CapabilityShader }); + ADD_VEC_INIT(CapabilityStorageImageMultisample, { CapabilityShader }); + ADD_VEC_INIT(CapabilityUniformBufferArrayDynamicIndexing, { CapabilityShader }); + ADD_VEC_INIT(CapabilitySampledImageArrayDynamicIndexing, { CapabilityShader }); + ADD_VEC_INIT(CapabilityStorageBufferArrayDynamicIndexing, { CapabilityShader }); + ADD_VEC_INIT(CapabilityStorageImageArrayDynamicIndexing, { CapabilityShader }); + ADD_VEC_INIT(CapabilityClipDistance, { CapabilityShader }); + ADD_VEC_INIT(CapabilityCullDistance, { CapabilityShader }); + ADD_VEC_INIT(CapabilityImageCubeArray, { CapabilitySampledCubeArray }); + ADD_VEC_INIT(CapabilitySampleRateShading, { CapabilityShader }); + ADD_VEC_INIT(CapabilityImageRect, { CapabilitySampledRect }); + ADD_VEC_INIT(CapabilitySampledRect, { CapabilityShader }); + ADD_VEC_INIT(CapabilityGenericPointer, { CapabilityAddresses }); + ADD_VEC_INIT(CapabilityInt8, { CapabilityKernel }); + ADD_VEC_INIT(CapabilityInputAttachment, { CapabilityShader }); + ADD_VEC_INIT(CapabilitySparseResidency, { CapabilityShader }); + ADD_VEC_INIT(CapabilityMinLod, { CapabilityShader }); + ADD_VEC_INIT(CapabilityImage1D, { CapabilitySampled1D }); + ADD_VEC_INIT(CapabilitySampledCubeArray, { CapabilityShader }); + ADD_VEC_INIT(CapabilityImageBuffer, { CapabilitySampledBuffer }); + ADD_VEC_INIT(CapabilityImageMSArray, { CapabilityShader }); + ADD_VEC_INIT(CapabilityStorageImageExtendedFormats, { CapabilityShader }); + ADD_VEC_INIT(CapabilityImageQuery, { CapabilityShader }); + ADD_VEC_INIT(CapabilityDerivativeControl, { CapabilityShader }); + ADD_VEC_INIT(CapabilityInterpolationFunction, { CapabilityShader }); + ADD_VEC_INIT(CapabilityTransformFeedback, { CapabilityShader }); + ADD_VEC_INIT(CapabilityGeometryStreams, { CapabilityGeometry }); + ADD_VEC_INIT(CapabilityStorageImageReadWithoutFormat, { CapabilityShader }); + ADD_VEC_INIT(CapabilityStorageImageWriteWithoutFormat, { CapabilityShader }); + ADD_VEC_INIT(CapabilityMultiViewport, { CapabilityGeometry }); +} + +template<> inline void +SPIRVMap<SPIRVExecutionModelKind, SPIRVCapVec>::init() { + ADD_VEC_INIT(ExecutionModelVertex, { CapabilityShader }); + ADD_VEC_INIT(ExecutionModelTessellationControl, { CapabilityTessellation }); + ADD_VEC_INIT(ExecutionModelTessellationEvaluation, { CapabilityTessellation }); + ADD_VEC_INIT(ExecutionModelGeometry, { CapabilityGeometry }); + ADD_VEC_INIT(ExecutionModelFragment, { CapabilityShader }); + ADD_VEC_INIT(ExecutionModelGLCompute, { CapabilityShader }); + ADD_VEC_INIT(ExecutionModelKernel, { CapabilityKernel }); +} + +template<> inline void +SPIRVMap<SPIRVExecutionModeKind, SPIRVCapVec>::init() { + ADD_VEC_INIT(ExecutionModeInvocations, { CapabilityGeometry }); + ADD_VEC_INIT(ExecutionModeSpacingEqual, { CapabilityTessellation }); + ADD_VEC_INIT(ExecutionModeSpacingFractionalEven, { CapabilityTessellation }); + ADD_VEC_INIT(ExecutionModeSpacingFractionalOdd, { CapabilityTessellation }); + ADD_VEC_INIT(ExecutionModeVertexOrderCw, { CapabilityTessellation }); + ADD_VEC_INIT(ExecutionModeVertexOrderCcw, { CapabilityTessellation }); + ADD_VEC_INIT(ExecutionModePixelCenterInteger, { CapabilityShader }); + ADD_VEC_INIT(ExecutionModeOriginUpperLeft, { CapabilityShader }); + ADD_VEC_INIT(ExecutionModeOriginLowerLeft, { CapabilityShader }); + ADD_VEC_INIT(ExecutionModeEarlyFragmentTests, { CapabilityShader }); + ADD_VEC_INIT(ExecutionModePointMode, { CapabilityTessellation }); + ADD_VEC_INIT(ExecutionModeXfb, { CapabilityTransformFeedback }); + ADD_VEC_INIT(ExecutionModeDepthReplacing, { CapabilityShader }); + ADD_VEC_INIT(ExecutionModeDepthGreater, { CapabilityShader }); + ADD_VEC_INIT(ExecutionModeDepthLess, { CapabilityShader }); + ADD_VEC_INIT(ExecutionModeDepthUnchanged, { CapabilityShader }); + ADD_VEC_INIT(ExecutionModeLocalSizeHint, { CapabilityKernel }); + ADD_VEC_INIT(ExecutionModeInputPoints, { CapabilityGeometry }); + ADD_VEC_INIT(ExecutionModeInputLines, { CapabilityGeometry }); + ADD_VEC_INIT(ExecutionModeInputLinesAdjacency, { CapabilityGeometry }); + ADD_VEC_INIT(ExecutionModeTriangles, { CapabilityGeometry, CapabilityTessellation }); + ADD_VEC_INIT(ExecutionModeInputTrianglesAdjacency, { CapabilityGeometry }); + ADD_VEC_INIT(ExecutionModeQuads, { CapabilityTessellation }); + ADD_VEC_INIT(ExecutionModeIsolines, { CapabilityTessellation }); + ADD_VEC_INIT(ExecutionModeOutputVertices, { CapabilityGeometry, CapabilityTessellation }); + ADD_VEC_INIT(ExecutionModeOutputPoints, { CapabilityGeometry }); + ADD_VEC_INIT(ExecutionModeOutputLineStrip, { CapabilityGeometry }); + ADD_VEC_INIT(ExecutionModeOutputTriangleStrip, { CapabilityGeometry }); + ADD_VEC_INIT(ExecutionModeVecTypeHint, { CapabilityKernel }); + ADD_VEC_INIT(ExecutionModeContractionOff, { CapabilityKernel }); +} + +template<> inline void +SPIRVMap<SPIRVMemoryModelKind, SPIRVCapVec>::init() { + ADD_VEC_INIT(MemoryModelSimple, { CapabilityShader }); + ADD_VEC_INIT(MemoryModelGLSL450, { CapabilityShader }); + ADD_VEC_INIT(MemoryModelOpenCL, { CapabilityKernel }); +} + +template<> inline void +SPIRVMap<SPIRVStorageClassKind, SPIRVCapVec>::init() { + ADD_VEC_INIT(StorageClassInput, { CapabilityShader }); + ADD_VEC_INIT(StorageClassUniform, { CapabilityShader }); + ADD_VEC_INIT(StorageClassOutput, { CapabilityShader }); + ADD_VEC_INIT(StorageClassPrivate, { CapabilityShader }); + ADD_VEC_INIT(StorageClassGeneric, { CapabilityGenericPointer }); + ADD_VEC_INIT(StorageClassPushConstant, { CapabilityShader }); + ADD_VEC_INIT(StorageClassAtomicCounter, { CapabilityAtomicStorage }); +} + +template<> inline void +SPIRVMap<SPIRVImageDimKind, SPIRVCapVec>::init() { + ADD_VEC_INIT(Dim1D, { CapabilitySampled1D }); + ADD_VEC_INIT(DimCube, { CapabilityShader }); + ADD_VEC_INIT(DimRect, { CapabilitySampledRect }); + ADD_VEC_INIT(DimBuffer, { CapabilitySampledBuffer }); + ADD_VEC_INIT(DimSubpassData, {CapabilityInputAttachment }); +} + +template<> inline void +SPIRVMap<ImageFormat, SPIRVCapVec>::init() { + ADD_VEC_INIT(ImageFormatRgba32f, { CapabilityShader }); + ADD_VEC_INIT(ImageFormatRgba16f, { CapabilityShader }); + ADD_VEC_INIT(ImageFormatR32f, { CapabilityShader }); + ADD_VEC_INIT(ImageFormatRgba8, { CapabilityShader }); + ADD_VEC_INIT(ImageFormatRgba8Snorm, { CapabilityShader }); + ADD_VEC_INIT(ImageFormatRg32f, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRg16f, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatR11fG11fB10f, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatR16f, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRgba16, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRgb10A2, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRg16, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRg8, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatR16, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatR8, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRgba16Snorm, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRg16Snorm, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRg8Snorm, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatR16Snorm, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatR8Snorm, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRgba32i, { CapabilityShader }); + ADD_VEC_INIT(ImageFormatRgba16i, { CapabilityShader }); + ADD_VEC_INIT(ImageFormatRgba8i, { CapabilityShader }); + ADD_VEC_INIT(ImageFormatR32i, { CapabilityShader }); + ADD_VEC_INIT(ImageFormatRg32i, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRg16i, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRg8i, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatR16i, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatR8i, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRgba32ui, { CapabilityShader }); + ADD_VEC_INIT(ImageFormatRgba16ui, { CapabilityShader }); + ADD_VEC_INIT(ImageFormatRgba8ui, { CapabilityShader }); + ADD_VEC_INIT(ImageFormatR32ui, { CapabilityShader }); + ADD_VEC_INIT(ImageFormatRgb10a2ui, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRg32ui, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatRg16ui, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatR16ui, { CapabilityStorageImageExtendedFormats }); + ADD_VEC_INIT(ImageFormatR8ui, { CapabilityStorageImageExtendedFormats }); +} + +template<> inline void +SPIRVMap<ImageOperandsMask, SPIRVCapVec>::init() { + ADD_VEC_INIT(ImageOperandsBiasMask, { CapabilityShader }); + ADD_VEC_INIT(ImageOperandsOffsetMask, { CapabilityImageGatherExtended }); + ADD_VEC_INIT(ImageOperandsMinLodMask, { CapabilityMinLod }); +} + +template<> inline void +SPIRVMap<Decoration, SPIRVCapVec>::init() { + ADD_VEC_INIT(DecorationRelaxedPrecision, { CapabilityShader }); + ADD_VEC_INIT(DecorationSpecId, { CapabilityShader }); + ADD_VEC_INIT(DecorationBlock, { CapabilityShader }); + ADD_VEC_INIT(DecorationBufferBlock, { CapabilityShader }); + ADD_VEC_INIT(DecorationRowMajor, { CapabilityMatrix }); + ADD_VEC_INIT(DecorationColMajor, { CapabilityMatrix }); + ADD_VEC_INIT(DecorationArrayStride, { CapabilityShader }); + ADD_VEC_INIT(DecorationMatrixStride, { CapabilityMatrix }); + ADD_VEC_INIT(DecorationGLSLShared, { CapabilityShader }); + ADD_VEC_INIT(DecorationGLSLPacked, { CapabilityShader }); + ADD_VEC_INIT(DecorationCPacked, { CapabilityKernel }); + ADD_VEC_INIT(DecorationNoPerspective, { CapabilityShader }); + ADD_VEC_INIT(DecorationFlat, { CapabilityShader }); + ADD_VEC_INIT(DecorationPatch, { CapabilityTessellation }); + ADD_VEC_INIT(DecorationCentroid, { CapabilityShader }); + ADD_VEC_INIT(DecorationSample, { CapabilitySampleRateShading }); + ADD_VEC_INIT(DecorationInvariant, { CapabilityShader }); + ADD_VEC_INIT(DecorationConstant, { CapabilityKernel }); + ADD_VEC_INIT(DecorationUniform, { CapabilityShader }); + ADD_VEC_INIT(DecorationSaturatedConversion, { CapabilityKernel }); + ADD_VEC_INIT(DecorationStream, { CapabilityGeometryStreams }); + ADD_VEC_INIT(DecorationLocation, { CapabilityShader }); + ADD_VEC_INIT(DecorationComponent, { CapabilityShader }); + ADD_VEC_INIT(DecorationIndex, { CapabilityShader }); + ADD_VEC_INIT(DecorationBinding, { CapabilityShader }); + ADD_VEC_INIT(DecorationDescriptorSet, { CapabilityShader }); + ADD_VEC_INIT(DecorationOffset, { CapabilityShader }); + ADD_VEC_INIT(DecorationXfbBuffer, { CapabilityTransformFeedback }); + ADD_VEC_INIT(DecorationXfbStride, { CapabilityTransformFeedback }); + ADD_VEC_INIT(DecorationFuncParamAttr, { CapabilityKernel }); + ADD_VEC_INIT(DecorationFPRoundingMode, { CapabilityKernel }); + ADD_VEC_INIT(DecorationFPFastMathMode, { CapabilityKernel }); + ADD_VEC_INIT(DecorationLinkageAttributes, { CapabilityLinkage }); + ADD_VEC_INIT(DecorationNoContraction, { CapabilityShader }); + ADD_VEC_INIT(DecorationInputAttachmentIndex, { CapabilityInputAttachment }); + ADD_VEC_INIT(DecorationAlignment, { CapabilityKernel }); +} + +template<> inline void +SPIRVMap<BuiltIn, SPIRVCapVec>::init() { + ADD_VEC_INIT(BuiltInPosition, { CapabilityShader }); + ADD_VEC_INIT(BuiltInPointSize, { CapabilityShader }); + ADD_VEC_INIT(BuiltInClipDistance, { CapabilityClipDistance }); + ADD_VEC_INIT(BuiltInCullDistance, { CapabilityCullDistance }); + ADD_VEC_INIT(BuiltInVertexId, { CapabilityShader }); + ADD_VEC_INIT(BuiltInInstanceId, { CapabilityShader }); + ADD_VEC_INIT(BuiltInPrimitiveId, { CapabilityGeometry, CapabilityTessellation }); + ADD_VEC_INIT(BuiltInInvocationId, { CapabilityGeometry, CapabilityTessellation }); + ADD_VEC_INIT(BuiltInLayer, { CapabilityGeometry }); + ADD_VEC_INIT(BuiltInViewportIndex, { CapabilityMultiViewport }); + ADD_VEC_INIT(BuiltInTessLevelOuter, { CapabilityTessellation }); + ADD_VEC_INIT(BuiltInTessLevelInner, { CapabilityTessellation }); + ADD_VEC_INIT(BuiltInTessCoord, { CapabilityTessellation }); + ADD_VEC_INIT(BuiltInPatchVertices, { CapabilityTessellation }); + ADD_VEC_INIT(BuiltInFragCoord, { CapabilityShader }); + ADD_VEC_INIT(BuiltInPointCoord, { CapabilityShader }); + ADD_VEC_INIT(BuiltInFrontFacing, { CapabilityShader }); + ADD_VEC_INIT(BuiltInSampleId, { CapabilitySampleRateShading }); + ADD_VEC_INIT(BuiltInSamplePosition, { CapabilitySampleRateShading }); + ADD_VEC_INIT(BuiltInSampleMask, { CapabilitySampleRateShading }); + ADD_VEC_INIT(BuiltInFragDepth, { CapabilityShader }); + ADD_VEC_INIT(BuiltInHelperInvocation, { CapabilityShader }); + ADD_VEC_INIT(BuiltInWorkDim, { CapabilityKernel }); + ADD_VEC_INIT(BuiltInGlobalSize, { CapabilityKernel }); + ADD_VEC_INIT(BuiltInEnqueuedWorkgroupSize, { CapabilityKernel }); + ADD_VEC_INIT(BuiltInGlobalOffset, { CapabilityKernel }); + ADD_VEC_INIT(BuiltInGlobalLinearId, { CapabilityKernel }); + ADD_VEC_INIT(BuiltInSubgroupSize, { CapabilityKernel }); + ADD_VEC_INIT(BuiltInSubgroupMaxSize, { CapabilityKernel }); + ADD_VEC_INIT(BuiltInNumSubgroups, { CapabilityKernel }); + ADD_VEC_INIT(BuiltInNumEnqueuedSubgroups, { CapabilityKernel }); + ADD_VEC_INIT(BuiltInSubgroupId, { CapabilityKernel }); + ADD_VEC_INIT(BuiltInSubgroupLocalInvocationId, { CapabilityKernel }); + ADD_VEC_INIT(BuiltInVertexIndex, { CapabilityShader }); + ADD_VEC_INIT(BuiltInInstanceIndex, { CapabilityShader }); +} + +template<> inline void +SPIRVMap<MemorySemanticsMask, SPIRVCapVec>::init() { + ADD_VEC_INIT(MemorySemanticsUniformMemoryMask, { CapabilityShader }); + ADD_VEC_INIT(MemorySemanticsAtomicCounterMemoryMask, { CapabilityAtomicStorage }); +} + +#undef ADD_VEC_INIT + +inline unsigned +getImageDimension(SPIRVImageDimKind K) { + switch(K){ + case Dim1D: return 1; + case Dim2D: return 2; + case Dim3D: return 3; + case DimCube: return 2; + case DimRect: return 2; + case DimBuffer: return 1; + default: return 0; + } +} + +/// Extract memory order part of SPIR-V memory semantics. +inline unsigned +extractSPIRVMemOrderSemantic(unsigned Sema) { + return Sema & kSPIRVMemOrderSemanticMask; +} + + +} + + +#endif /* SPIRVENUM_HPP_ */ diff --git a/lib/SPIRV/libSPIRV/SPIRVError.h b/lib/SPIRV/libSPIRV/SPIRVError.h index 45229ff..080ed99 100644 --- a/lib/SPIRV/libSPIRV/SPIRVError.h +++ b/lib/SPIRV/libSPIRV/SPIRVError.h @@ -1,127 +1,127 @@ -//===- SPIRVError.h - SPIR-V error code and checking -------------*- 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 defines SPIRV error code and checking utility.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVERROR_HPP_
-#define SPIRVERROR_HPP_
-
-#include "SPIRVUtil.h"
-#include "SPIRVDebug.h"
-#include <string>
-#include <sstream>
-
-namespace SPIRV{
-
-// Check condition and set error code and error msg.
-// To use this macro, function checkError must be defined in the scope.
-#define SPIRVCK(Condition,ErrCode,ErrMsg) \
- getErrorLog().checkError(Condition, SPIRVEC_##ErrCode, std::string()+ErrMsg,\
- #Condition, __FILE__, __LINE__)
-
-// Check condition and set error code and error msg. If fail returns false.
-#define SPIRVCKRT(Condition,ErrCode,ErrMsg) \
- if (!getErrorLog().checkError(Condition, SPIRVEC_##ErrCode,\
- std::string()+ErrMsg, #Condition, __FILE__, __LINE__))\
- return false;
-
-// Defines error code enum type SPIRVErrorCode.
-enum SPIRVErrorCode {
-#define _SPIRV_OP(x,y) SPIRVEC_##x,
-#include "SPIRVErrorEnum.h"
-#undef _SPIRV_OP
-};
-
-// Defines OpErorMap which maps error code to a string describing the error.
-template<> inline void
-SPIRVMap<SPIRVErrorCode, std::string>::init() {
-#define _SPIRV_OP(x,y) add(SPIRVEC_##x, std::string(#x)+": "+y);
-#include "SPIRVErrorEnum.h"
-#undef _SPIRV_OP
-}
-
-typedef SPIRVMap<SPIRVErrorCode, std::string> SPIRVErrorMap;
-
-class SPIRVErrorLog {
-public:
- SPIRVErrorLog():ErrorCode(SPIRVEC_Success){}
- SPIRVErrorCode getError(std::string& ErrMsg) {
- ErrMsg = ErrorMsg;
- return ErrorCode;
- }
- void setError(SPIRVErrorCode ErrCode, const std::string& ErrMsg) {
- ErrorCode = ErrCode;
- ErrorMsg = ErrMsg;
- }
- // Check if Condition is satisfied and set ErrCode and DetailedMsg
- // if not. Returns true if no error.
- bool checkError(bool Condition, SPIRVErrorCode ErrCode,
- const std::string& DetailedMsg = "",
- const char *CondString = nullptr,
- const char *FileName = nullptr,
- unsigned LineNumber = 0);
-protected:
- SPIRVErrorCode ErrorCode;
- std::string ErrorMsg;
-
-};
-
-inline bool
-SPIRVErrorLog::checkError(bool Cond, SPIRVErrorCode ErrCode,
- const std::string& Msg, const char *CondString, const char *FileName,
- unsigned LineNo) {
- std::stringstream SS;
- if (Cond)
- return Cond;
- // Do not overwrite previous failure.
- if (ErrorCode != SPIRVEC_Success)
- return Cond;
- SS << SPIRVErrorMap::map(ErrCode) << " " << Msg;
- if (SPIRVDbgErrorMsgIncludesSourceInfo)
- SS <<" [Src: " << FileName << ":" << LineNo << " " << CondString << " ]";
- setError(ErrCode, SS.str());
- if (SPIRVDbgAssertOnError) {
- spvdbgs() << SS.str() << '\n';
- spvdbgs().flush();
- assert (0);
- }
- return Cond;
-}
-
-}
-
-
-#endif /* SPIRVERROR_HPP_ */
+//===- SPIRVError.h - SPIR-V error code and checking -------------*- 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 defines SPIRV error code and checking utility. +// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVERROR_HPP_ +#define SPIRVERROR_HPP_ + +#include "SPIRVUtil.h" +#include "SPIRVDebug.h" +#include <string> +#include <sstream> + +namespace SPIRV{ + +// Check condition and set error code and error msg. +// To use this macro, function checkError must be defined in the scope. +#define SPIRVCK(Condition,ErrCode,ErrMsg) \ + getErrorLog().checkError(Condition, SPIRVEC_##ErrCode, std::string()+ErrMsg,\ + #Condition, __FILE__, __LINE__) + +// Check condition and set error code and error msg. If fail returns false. +#define SPIRVCKRT(Condition,ErrCode,ErrMsg) \ + if (!getErrorLog().checkError(Condition, SPIRVEC_##ErrCode,\ + std::string()+ErrMsg, #Condition, __FILE__, __LINE__))\ + return false; + +// Defines error code enum type SPIRVErrorCode. +enum SPIRVErrorCode { +#define _SPIRV_OP(x,y) SPIRVEC_##x, +#include "SPIRVErrorEnum.h" +#undef _SPIRV_OP +}; + +// Defines OpErorMap which maps error code to a string describing the error. +template<> inline void +SPIRVMap<SPIRVErrorCode, std::string>::init() { +#define _SPIRV_OP(x,y) add(SPIRVEC_##x, std::string(#x)+": "+y); +#include "SPIRVErrorEnum.h" +#undef _SPIRV_OP +} + +typedef SPIRVMap<SPIRVErrorCode, std::string> SPIRVErrorMap; + +class SPIRVErrorLog { +public: + SPIRVErrorLog():ErrorCode(SPIRVEC_Success){} + SPIRVErrorCode getError(std::string& ErrMsg) { + ErrMsg = ErrorMsg; + return ErrorCode; + } + void setError(SPIRVErrorCode ErrCode, const std::string& ErrMsg) { + ErrorCode = ErrCode; + ErrorMsg = ErrMsg; + } + // Check if Condition is satisfied and set ErrCode and DetailedMsg + // if not. Returns true if no error. + bool checkError(bool Condition, SPIRVErrorCode ErrCode, + const std::string& DetailedMsg = "", + const char *CondString = nullptr, + const char *FileName = nullptr, + unsigned LineNumber = 0); +protected: + SPIRVErrorCode ErrorCode; + std::string ErrorMsg; + +}; + +inline bool +SPIRVErrorLog::checkError(bool Cond, SPIRVErrorCode ErrCode, + const std::string& Msg, const char *CondString, const char *FileName, + unsigned LineNo) { + std::stringstream SS; + if (Cond) + return Cond; + // Do not overwrite previous failure. + if (ErrorCode != SPIRVEC_Success) + return Cond; + SS << SPIRVErrorMap::map(ErrCode) << " " << Msg; + if (SPIRVDbgErrorMsgIncludesSourceInfo) + SS <<" [Src: " << FileName << ":" << LineNo << " " << CondString << " ]"; + setError(ErrCode, SS.str()); + if (SPIRVDbgAssertOnError) { + spvdbgs() << SS.str() << '\n'; + spvdbgs().flush(); + assert (0); + } + return Cond; +} + +} + + +#endif /* SPIRVERROR_HPP_ */ diff --git a/lib/SPIRV/libSPIRV/SPIRVExtInst.h b/lib/SPIRV/libSPIRV/SPIRVExtInst.h index 0b287ea..b73d85d 100644 --- a/lib/SPIRV/libSPIRV/SPIRVExtInst.h +++ b/lib/SPIRV/libSPIRV/SPIRVExtInst.h @@ -1,275 +1,275 @@ -//===- SPIRVBuiltin.h - SPIR-V extended instruction --------------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines SPIR-V extended instructions.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVBUILTIN_HPP_
-#define SPIRVBUILTIN_HPP_
-
-#include "SPIRVUtil.h"
-#include "OpenCL.std.h"
-
-#include <string>
-#include <vector>
-
-namespace SPIRV{
-
-
-inline bool
-isOpenCLBuiltinSet (SPIRVExtInstSetKind Set) {
- return Set == SPIRVEIS_OpenCL;
-}
-
-typedef OpenCLLIB::Entrypoints OCLExtOpKind;
-
-template<> inline void
-SPIRVMap<OCLExtOpKind, std::string>::init() {
- add(OpenCLLIB::Acos, "acos");
- add(OpenCLLIB::Acosh, "acosh");
- add(OpenCLLIB::Acospi, "acospi");
- add(OpenCLLIB::Asin, "asin");
- add(OpenCLLIB::Asinh, "asinh");
- add(OpenCLLIB::Asinpi, "asinpi");
- add(OpenCLLIB::Atan, "atan");
- add(OpenCLLIB::Atan2, "atan2");
- add(OpenCLLIB::Atanh, "atanh");
- add(OpenCLLIB::Atanpi, "atanpi");
- add(OpenCLLIB::Atan2pi, "atan2pi");
- add(OpenCLLIB::Cbrt, "cbrt");
- add(OpenCLLIB::Ceil, "ceil");
- add(OpenCLLIB::Copysign, "copysign");
- add(OpenCLLIB::Cos, "cos");
- add(OpenCLLIB::Cosh, "cosh");
- add(OpenCLLIB::Cospi, "cospi");
- add(OpenCLLIB::Erfc, "erfc");
- add(OpenCLLIB::Erf, "erf");
- add(OpenCLLIB::Exp, "exp");
- add(OpenCLLIB::Exp2, "exp2");
- add(OpenCLLIB::Exp10, "exp10");
- add(OpenCLLIB::Expm1, "expm1");
- add(OpenCLLIB::Fabs, "fabs");
- add(OpenCLLIB::Fdim, "fdim");
- add(OpenCLLIB::Floor, "floor");
- add(OpenCLLIB::Fma, "fma");
- add(OpenCLLIB::Fmax, "fmax");
- add(OpenCLLIB::Fmin, "fmin");
- add(OpenCLLIB::Fmod, "fmod");
- add(OpenCLLIB::Fract, "fract");
- add(OpenCLLIB::Frexp, "frexp");
- add(OpenCLLIB::Hypot, "hypot");
- add(OpenCLLIB::Ilogb, "ilogb");
- add(OpenCLLIB::Ldexp, "ldexp");
- add(OpenCLLIB::Lgamma, "lgamma");
- add(OpenCLLIB::Lgamma_r, "lgamma_r");
- add(OpenCLLIB::Log, "log");
- add(OpenCLLIB::Log2, "log2");
- add(OpenCLLIB::Log10, "log10");
- add(OpenCLLIB::Log1p, "log1p");
- add(OpenCLLIB::Logb, "logb");
- add(OpenCLLIB::Mad, "mad");
- add(OpenCLLIB::Maxmag, "maxmag");
- add(OpenCLLIB::Minmag, "minmag");
- add(OpenCLLIB::Modf, "modf");
- add(OpenCLLIB::Nan, "nan");
- add(OpenCLLIB::Nextafter, "nextafter");
- add(OpenCLLIB::Pow, "pow");
- add(OpenCLLIB::Pown, "pown");
- add(OpenCLLIB::Powr, "powr");
- add(OpenCLLIB::Remainder, "remainder");
- add(OpenCLLIB::Remquo, "remquo");
- add(OpenCLLIB::Rint, "rint");
- add(OpenCLLIB::Rootn, "rootn");
- add(OpenCLLIB::Round, "round");
- add(OpenCLLIB::Rsqrt, "rsqrt");
- add(OpenCLLIB::Sin, "sin");
- add(OpenCLLIB::Sincos, "sincos");
- add(OpenCLLIB::Sinh, "sinh");
- add(OpenCLLIB::Sinpi, "sinpi");
- add(OpenCLLIB::Sqrt, "sqrt");
- add(OpenCLLIB::Tan, "tan");
- add(OpenCLLIB::Tanh, "tanh");
- add(OpenCLLIB::Tanpi, "tanpi");
- add(OpenCLLIB::Tgamma, "tgamma");
- add(OpenCLLIB::Trunc, "trunc");
- add(OpenCLLIB::Half_cos, "half_cos");
- add(OpenCLLIB::Half_divide, "half_divide");
- add(OpenCLLIB::Half_exp, "half_exp");
- add(OpenCLLIB::Half_exp2, "half_exp2");
- add(OpenCLLIB::Half_exp10, "half_exp10");
- add(OpenCLLIB::Half_log, "half_log");
- add(OpenCLLIB::Half_log2, "half_log2");
- add(OpenCLLIB::Half_log10, "half_log10");
- add(OpenCLLIB::Half_powr, "half_powr");
- add(OpenCLLIB::Half_recip, "half_recip");
- add(OpenCLLIB::Half_rsqrt, "half_rsqrt");
- add(OpenCLLIB::Half_sin, "half_sin");
- add(OpenCLLIB::Half_sqrt, "half_sqrt");
- add(OpenCLLIB::Half_tan, "half_tan");
- add(OpenCLLIB::Native_cos, "native_cos");
- add(OpenCLLIB::Native_divide, "native_divide");
- add(OpenCLLIB::Native_exp, "native_exp");
- add(OpenCLLIB::Native_exp2, "native_exp2");
- add(OpenCLLIB::Native_exp10, "native_exp10");
- add(OpenCLLIB::Native_log, "native_log");
- add(OpenCLLIB::Native_log2, "native_log2");
- add(OpenCLLIB::Native_log10, "native_log10");
- add(OpenCLLIB::Native_powr, "native_powr");
- add(OpenCLLIB::Native_recip, "native_recip");
- add(OpenCLLIB::Native_rsqrt, "native_rsqrt");
- add(OpenCLLIB::Native_sin, "native_sin");
- add(OpenCLLIB::Native_sqrt, "native_sqrt");
- add(OpenCLLIB::Native_tan, "native_tan");
- add(OpenCLLIB::FClamp, "fclamp");
- add(OpenCLLIB::Degrees, "degrees");
- add(OpenCLLIB::Mix, "mix");
- add(OpenCLLIB::FMax_common, "fmax_common");
- add(OpenCLLIB::FMin_common, "fmin_common");
- add(OpenCLLIB::Radians, "radians");
- add(OpenCLLIB::Step, "step");
- add(OpenCLLIB::Smoothstep, "smoothstep");
- add(OpenCLLIB::Sign, "sign");
- add(OpenCLLIB::Cross, "cross");
- add(OpenCLLIB::Distance, "distance");
- add(OpenCLLIB::Length, "length");
- add(OpenCLLIB::Normalize, "normalize");
- add(OpenCLLIB::Fast_distance, "fast_distance");
- add(OpenCLLIB::Fast_length, "fast_length");
- add(OpenCLLIB::Fast_normalize, "fast_normalize");
- add(OpenCLLIB::Read_imagef, "read_imagef");
- add(OpenCLLIB::Read_imagei, "read_imagei");
- add(OpenCLLIB::Read_imageui, "read_imageui");
- add(OpenCLLIB::Read_imageh, "read_imageh");
- add(OpenCLLIB::Read_imagef_samplerless, "read_imagef_samplerless");
- add(OpenCLLIB::Read_imagei_samplerless, "read_imagei_samplerless");
- add(OpenCLLIB::Read_imageui_samplerless, "read_imageui_samplerless");
- add(OpenCLLIB::Read_imageh_samplerless, "read_imageh_samplerless");
- add(OpenCLLIB::Write_imagef, "write_imagef");
- add(OpenCLLIB::Write_imagei, "write_imagei");
- add(OpenCLLIB::Write_imageui, "write_imageui");
- add(OpenCLLIB::Write_imageh, "write_imageh");
- add(OpenCLLIB::Read_imagef_mipmap_lod, "read_imagef_mipmap_lod");
- add(OpenCLLIB::Read_imagei_mipmap_lod, "read_imagei_mipmap_lod");
- add(OpenCLLIB::Read_imageui_mipmap_lod, "read_imageui_mipmap_lod");
- add(OpenCLLIB::Read_imagef_mipmap_grad, "read_imagef_mipmap_gradient");
- add(OpenCLLIB::Read_imagei_mipmap_grad, "read_imagei_mipmap_gradient");
- add(OpenCLLIB::Read_imageui_mipmap_grad, "read_imageui_mipmap_gradient");
- add(OpenCLLIB::Write_imagef_mipmap_lod, "write_imagef_mipmap_lod");
- add(OpenCLLIB::Write_imagei_mipmap_lod, "write_imagei_mipmap_lod");
- add(OpenCLLIB::Write_imageui_mipmap_lod, "write_imageui_mipmap_lod");
- add(OpenCLLIB::Get_image_width, "get_image_width");
- add(OpenCLLIB::Get_image_height, "get_image_height");
- add(OpenCLLIB::Get_image_depth, "get_image_depth");
- add(OpenCLLIB::Get_image_channel_data_type, "get_image_channel_data_type");
- add(OpenCLLIB::Get_image_channel_order, "get_image_channel_order");
- add(OpenCLLIB::Get_image_dim, "get_image_dim");
- add(OpenCLLIB::Get_image_array_size, "get_image_array_size");
- add(OpenCLLIB::Get_image_num_samples, "get_image_num_samples");
- add(OpenCLLIB::Get_image_num_mip_levels, "get_image_num_mip_levels");
- add(OpenCLLIB::SAbs, "s_abs");
- add(OpenCLLIB::SAbs_diff, "s_abs_diff");
- add(OpenCLLIB::SAdd_sat, "s_add_sat");
- add(OpenCLLIB::UAdd_sat, "u_add_sat");
- add(OpenCLLIB::SHadd, "s_hadd");
- add(OpenCLLIB::UHadd, "u_hadd");
- add(OpenCLLIB::SRhadd, "s_rhadd");
- add(OpenCLLIB::URhadd, "u_rhadd");
- add(OpenCLLIB::SClamp, "s_clamp");
- add(OpenCLLIB::UClamp, "u_clamp");
- add(OpenCLLIB::Clz, "clz");
- add(OpenCLLIB::Ctz, "ctz");
- add(OpenCLLIB::SMad_hi, "s_mad_hi");
- add(OpenCLLIB::SMad_sat, "s_mad_sat");
- add(OpenCLLIB::UMad_sat, "u_mad_sat");
- add(OpenCLLIB::SMax, "s_max");
- add(OpenCLLIB::SMin, "s_min");
- add(OpenCLLIB::UMax, "u_max");
- add(OpenCLLIB::UMin, "u_min");
- add(OpenCLLIB::SMul_hi, "s_mul_hi");
- add(OpenCLLIB::Rotate, "rotate");
- add(OpenCLLIB::SSub_sat, "s_sub_sat");
- add(OpenCLLIB::USub_sat, "u_sub_sat");
- add(OpenCLLIB::U_Upsample, "u_upsample");
- add(OpenCLLIB::S_Upsample, "s_upsample");
- add(OpenCLLIB::Popcount, "popcount");
- add(OpenCLLIB::SMad24, "s_mad24");
- add(OpenCLLIB::UMad24, "u_mad24");
- add(OpenCLLIB::SMul24, "s_mul24");
- add(OpenCLLIB::UMul24, "u_mul24");
- add(OpenCLLIB::Vloadn, "vloadn");
- add(OpenCLLIB::Vstoren, "vstoren");
- add(OpenCLLIB::Vload_half, "vload_half");
- add(OpenCLLIB::Vload_halfn, "vload_halfn");
- add(OpenCLLIB::Vstore_half, "vstore_half");
- add(OpenCLLIB::Vstore_half_r, "vstore_half_r");
- add(OpenCLLIB::Vstore_halfn, "vstore_halfn");
- add(OpenCLLIB::Vstore_halfn_r, "vstore_halfn_r");
- add(OpenCLLIB::Vloada_halfn, "vloada_halfn");
- add(OpenCLLIB::Vstorea_halfn, "vstorea_halfn");
- add(OpenCLLIB::Vstorea_halfn_r, "vstorea_halfn_r");
- add(OpenCLLIB::Shuffle, "shuffle");
- add(OpenCLLIB::Shuffle2, "shuffle2");
- add(OpenCLLIB::Printf, "printf");
- add(OpenCLLIB::Prefetch, "prefetch");
- add(OpenCLLIB::Bitselect, "bitselect");
- add(OpenCLLIB::Select, "select");
- add(OpenCLLIB::UAbs, "u_abs");
- add(OpenCLLIB::UAbs_diff, "u_abs_diff");
- add(OpenCLLIB::UMul_hi, "u_mul_hi");
- add(OpenCLLIB::UMad_hi, "u_mad_hi");
-}
-SPIRV_DEF_NAMEMAP(OCLExtOpKind, OCLExtOpMap)
-
-inline bool
-isReadImage(SPIRVWord EntryPoint) {
- return EntryPoint >= OpenCLLIB::Read_imagef &&
- EntryPoint <= OpenCLLIB::Read_imageui;
-}
-
-inline bool
-isWriteImage(SPIRVWord EntryPoint) {
- return EntryPoint >= OpenCLLIB::Write_imagef &&
- EntryPoint <= OpenCLLIB::Write_imageui;
-}
-
-inline bool
-isReadOrWriteImage(SPIRVWord EntryPoint) {
- return isReadImage(EntryPoint) || isWriteImage(EntryPoint);
-}
-
-}
-
-#endif
+//===- SPIRVBuiltin.h - SPIR-V extended instruction --------------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines SPIR-V extended instructions. +/// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVBUILTIN_HPP_ +#define SPIRVBUILTIN_HPP_ + +#include "SPIRVUtil.h" +#include "OpenCL.std.h" + +#include <string> +#include <vector> + +namespace SPIRV{ + + +inline bool +isOpenCLBuiltinSet (SPIRVExtInstSetKind Set) { + return Set == SPIRVEIS_OpenCL; +} + +typedef OpenCLLIB::Entrypoints OCLExtOpKind; + +template<> inline void +SPIRVMap<OCLExtOpKind, std::string>::init() { + add(OpenCLLIB::Acos, "acos"); + add(OpenCLLIB::Acosh, "acosh"); + add(OpenCLLIB::Acospi, "acospi"); + add(OpenCLLIB::Asin, "asin"); + add(OpenCLLIB::Asinh, "asinh"); + add(OpenCLLIB::Asinpi, "asinpi"); + add(OpenCLLIB::Atan, "atan"); + add(OpenCLLIB::Atan2, "atan2"); + add(OpenCLLIB::Atanh, "atanh"); + add(OpenCLLIB::Atanpi, "atanpi"); + add(OpenCLLIB::Atan2pi, "atan2pi"); + add(OpenCLLIB::Cbrt, "cbrt"); + add(OpenCLLIB::Ceil, "ceil"); + add(OpenCLLIB::Copysign, "copysign"); + add(OpenCLLIB::Cos, "cos"); + add(OpenCLLIB::Cosh, "cosh"); + add(OpenCLLIB::Cospi, "cospi"); + add(OpenCLLIB::Erfc, "erfc"); + add(OpenCLLIB::Erf, "erf"); + add(OpenCLLIB::Exp, "exp"); + add(OpenCLLIB::Exp2, "exp2"); + add(OpenCLLIB::Exp10, "exp10"); + add(OpenCLLIB::Expm1, "expm1"); + add(OpenCLLIB::Fabs, "fabs"); + add(OpenCLLIB::Fdim, "fdim"); + add(OpenCLLIB::Floor, "floor"); + add(OpenCLLIB::Fma, "fma"); + add(OpenCLLIB::Fmax, "fmax"); + add(OpenCLLIB::Fmin, "fmin"); + add(OpenCLLIB::Fmod, "fmod"); + add(OpenCLLIB::Fract, "fract"); + add(OpenCLLIB::Frexp, "frexp"); + add(OpenCLLIB::Hypot, "hypot"); + add(OpenCLLIB::Ilogb, "ilogb"); + add(OpenCLLIB::Ldexp, "ldexp"); + add(OpenCLLIB::Lgamma, "lgamma"); + add(OpenCLLIB::Lgamma_r, "lgamma_r"); + add(OpenCLLIB::Log, "log"); + add(OpenCLLIB::Log2, "log2"); + add(OpenCLLIB::Log10, "log10"); + add(OpenCLLIB::Log1p, "log1p"); + add(OpenCLLIB::Logb, "logb"); + add(OpenCLLIB::Mad, "mad"); + add(OpenCLLIB::Maxmag, "maxmag"); + add(OpenCLLIB::Minmag, "minmag"); + add(OpenCLLIB::Modf, "modf"); + add(OpenCLLIB::Nan, "nan"); + add(OpenCLLIB::Nextafter, "nextafter"); + add(OpenCLLIB::Pow, "pow"); + add(OpenCLLIB::Pown, "pown"); + add(OpenCLLIB::Powr, "powr"); + add(OpenCLLIB::Remainder, "remainder"); + add(OpenCLLIB::Remquo, "remquo"); + add(OpenCLLIB::Rint, "rint"); + add(OpenCLLIB::Rootn, "rootn"); + add(OpenCLLIB::Round, "round"); + add(OpenCLLIB::Rsqrt, "rsqrt"); + add(OpenCLLIB::Sin, "sin"); + add(OpenCLLIB::Sincos, "sincos"); + add(OpenCLLIB::Sinh, "sinh"); + add(OpenCLLIB::Sinpi, "sinpi"); + add(OpenCLLIB::Sqrt, "sqrt"); + add(OpenCLLIB::Tan, "tan"); + add(OpenCLLIB::Tanh, "tanh"); + add(OpenCLLIB::Tanpi, "tanpi"); + add(OpenCLLIB::Tgamma, "tgamma"); + add(OpenCLLIB::Trunc, "trunc"); + add(OpenCLLIB::Half_cos, "half_cos"); + add(OpenCLLIB::Half_divide, "half_divide"); + add(OpenCLLIB::Half_exp, "half_exp"); + add(OpenCLLIB::Half_exp2, "half_exp2"); + add(OpenCLLIB::Half_exp10, "half_exp10"); + add(OpenCLLIB::Half_log, "half_log"); + add(OpenCLLIB::Half_log2, "half_log2"); + add(OpenCLLIB::Half_log10, "half_log10"); + add(OpenCLLIB::Half_powr, "half_powr"); + add(OpenCLLIB::Half_recip, "half_recip"); + add(OpenCLLIB::Half_rsqrt, "half_rsqrt"); + add(OpenCLLIB::Half_sin, "half_sin"); + add(OpenCLLIB::Half_sqrt, "half_sqrt"); + add(OpenCLLIB::Half_tan, "half_tan"); + add(OpenCLLIB::Native_cos, "native_cos"); + add(OpenCLLIB::Native_divide, "native_divide"); + add(OpenCLLIB::Native_exp, "native_exp"); + add(OpenCLLIB::Native_exp2, "native_exp2"); + add(OpenCLLIB::Native_exp10, "native_exp10"); + add(OpenCLLIB::Native_log, "native_log"); + add(OpenCLLIB::Native_log2, "native_log2"); + add(OpenCLLIB::Native_log10, "native_log10"); + add(OpenCLLIB::Native_powr, "native_powr"); + add(OpenCLLIB::Native_recip, "native_recip"); + add(OpenCLLIB::Native_rsqrt, "native_rsqrt"); + add(OpenCLLIB::Native_sin, "native_sin"); + add(OpenCLLIB::Native_sqrt, "native_sqrt"); + add(OpenCLLIB::Native_tan, "native_tan"); + add(OpenCLLIB::FClamp, "fclamp"); + add(OpenCLLIB::Degrees, "degrees"); + add(OpenCLLIB::Mix, "mix"); + add(OpenCLLIB::FMax_common, "fmax_common"); + add(OpenCLLIB::FMin_common, "fmin_common"); + add(OpenCLLIB::Radians, "radians"); + add(OpenCLLIB::Step, "step"); + add(OpenCLLIB::Smoothstep, "smoothstep"); + add(OpenCLLIB::Sign, "sign"); + add(OpenCLLIB::Cross, "cross"); + add(OpenCLLIB::Distance, "distance"); + add(OpenCLLIB::Length, "length"); + add(OpenCLLIB::Normalize, "normalize"); + add(OpenCLLIB::Fast_distance, "fast_distance"); + add(OpenCLLIB::Fast_length, "fast_length"); + add(OpenCLLIB::Fast_normalize, "fast_normalize"); + add(OpenCLLIB::Read_imagef, "read_imagef"); + add(OpenCLLIB::Read_imagei, "read_imagei"); + add(OpenCLLIB::Read_imageui, "read_imageui"); + add(OpenCLLIB::Read_imageh, "read_imageh"); + add(OpenCLLIB::Read_imagef_samplerless, "read_imagef_samplerless"); + add(OpenCLLIB::Read_imagei_samplerless, "read_imagei_samplerless"); + add(OpenCLLIB::Read_imageui_samplerless, "read_imageui_samplerless"); + add(OpenCLLIB::Read_imageh_samplerless, "read_imageh_samplerless"); + add(OpenCLLIB::Write_imagef, "write_imagef"); + add(OpenCLLIB::Write_imagei, "write_imagei"); + add(OpenCLLIB::Write_imageui, "write_imageui"); + add(OpenCLLIB::Write_imageh, "write_imageh"); + add(OpenCLLIB::Read_imagef_mipmap_lod, "read_imagef_mipmap_lod"); + add(OpenCLLIB::Read_imagei_mipmap_lod, "read_imagei_mipmap_lod"); + add(OpenCLLIB::Read_imageui_mipmap_lod, "read_imageui_mipmap_lod"); + add(OpenCLLIB::Read_imagef_mipmap_grad, "read_imagef_mipmap_gradient"); + add(OpenCLLIB::Read_imagei_mipmap_grad, "read_imagei_mipmap_gradient"); + add(OpenCLLIB::Read_imageui_mipmap_grad, "read_imageui_mipmap_gradient"); + add(OpenCLLIB::Write_imagef_mipmap_lod, "write_imagef_mipmap_lod"); + add(OpenCLLIB::Write_imagei_mipmap_lod, "write_imagei_mipmap_lod"); + add(OpenCLLIB::Write_imageui_mipmap_lod, "write_imageui_mipmap_lod"); + add(OpenCLLIB::Get_image_width, "get_image_width"); + add(OpenCLLIB::Get_image_height, "get_image_height"); + add(OpenCLLIB::Get_image_depth, "get_image_depth"); + add(OpenCLLIB::Get_image_channel_data_type, "get_image_channel_data_type"); + add(OpenCLLIB::Get_image_channel_order, "get_image_channel_order"); + add(OpenCLLIB::Get_image_dim, "get_image_dim"); + add(OpenCLLIB::Get_image_array_size, "get_image_array_size"); + add(OpenCLLIB::Get_image_num_samples, "get_image_num_samples"); + add(OpenCLLIB::Get_image_num_mip_levels, "get_image_num_mip_levels"); + add(OpenCLLIB::SAbs, "s_abs"); + add(OpenCLLIB::SAbs_diff, "s_abs_diff"); + add(OpenCLLIB::SAdd_sat, "s_add_sat"); + add(OpenCLLIB::UAdd_sat, "u_add_sat"); + add(OpenCLLIB::SHadd, "s_hadd"); + add(OpenCLLIB::UHadd, "u_hadd"); + add(OpenCLLIB::SRhadd, "s_rhadd"); + add(OpenCLLIB::URhadd, "u_rhadd"); + add(OpenCLLIB::SClamp, "s_clamp"); + add(OpenCLLIB::UClamp, "u_clamp"); + add(OpenCLLIB::Clz, "clz"); + add(OpenCLLIB::Ctz, "ctz"); + add(OpenCLLIB::SMad_hi, "s_mad_hi"); + add(OpenCLLIB::SMad_sat, "s_mad_sat"); + add(OpenCLLIB::UMad_sat, "u_mad_sat"); + add(OpenCLLIB::SMax, "s_max"); + add(OpenCLLIB::SMin, "s_min"); + add(OpenCLLIB::UMax, "u_max"); + add(OpenCLLIB::UMin, "u_min"); + add(OpenCLLIB::SMul_hi, "s_mul_hi"); + add(OpenCLLIB::Rotate, "rotate"); + add(OpenCLLIB::SSub_sat, "s_sub_sat"); + add(OpenCLLIB::USub_sat, "u_sub_sat"); + add(OpenCLLIB::U_Upsample, "u_upsample"); + add(OpenCLLIB::S_Upsample, "s_upsample"); + add(OpenCLLIB::Popcount, "popcount"); + add(OpenCLLIB::SMad24, "s_mad24"); + add(OpenCLLIB::UMad24, "u_mad24"); + add(OpenCLLIB::SMul24, "s_mul24"); + add(OpenCLLIB::UMul24, "u_mul24"); + add(OpenCLLIB::Vloadn, "vloadn"); + add(OpenCLLIB::Vstoren, "vstoren"); + add(OpenCLLIB::Vload_half, "vload_half"); + add(OpenCLLIB::Vload_halfn, "vload_halfn"); + add(OpenCLLIB::Vstore_half, "vstore_half"); + add(OpenCLLIB::Vstore_half_r, "vstore_half_r"); + add(OpenCLLIB::Vstore_halfn, "vstore_halfn"); + add(OpenCLLIB::Vstore_halfn_r, "vstore_halfn_r"); + add(OpenCLLIB::Vloada_halfn, "vloada_halfn"); + add(OpenCLLIB::Vstorea_halfn, "vstorea_halfn"); + add(OpenCLLIB::Vstorea_halfn_r, "vstorea_halfn_r"); + add(OpenCLLIB::Shuffle, "shuffle"); + add(OpenCLLIB::Shuffle2, "shuffle2"); + add(OpenCLLIB::Printf, "printf"); + add(OpenCLLIB::Prefetch, "prefetch"); + add(OpenCLLIB::Bitselect, "bitselect"); + add(OpenCLLIB::Select, "select"); + add(OpenCLLIB::UAbs, "u_abs"); + add(OpenCLLIB::UAbs_diff, "u_abs_diff"); + add(OpenCLLIB::UMul_hi, "u_mul_hi"); + add(OpenCLLIB::UMad_hi, "u_mad_hi"); +} +SPIRV_DEF_NAMEMAP(OCLExtOpKind, OCLExtOpMap) + +inline bool +isReadImage(SPIRVWord EntryPoint) { + return EntryPoint >= OpenCLLIB::Read_imagef && + EntryPoint <= OpenCLLIB::Read_imageui; +} + +inline bool +isWriteImage(SPIRVWord EntryPoint) { + return EntryPoint >= OpenCLLIB::Write_imagef && + EntryPoint <= OpenCLLIB::Write_imageui; +} + +inline bool +isReadOrWriteImage(SPIRVWord EntryPoint) { + return isReadImage(EntryPoint) || isWriteImage(EntryPoint); +} + +} + +#endif diff --git a/lib/SPIRV/libSPIRV/SPIRVFunction.cpp b/lib/SPIRV/libSPIRV/SPIRVFunction.cpp index 9c5c74b..1a3765b 100644 --- a/lib/SPIRV/libSPIRV/SPIRVFunction.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVFunction.cpp @@ -1,171 +1,171 @@ -//===- SPIRVFunction.cpp - Class to represent a SPIR-V Function --*- C++ -*-===//
-//
-// The LLVM/SPIRV Translator
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements Function class for SPIRV.
-//
-// 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.
-//
-//===----------------------------------------------------------------------===//
-
-#include "SPIRVEntry.h"
-#include "SPIRVFunction.h"
-#include "SPIRVBasicBlock.h"
-#include "SPIRVInstruction.h"
-#include "SPIRVStream.h"
-
-#include <functional>
-#include <algorithm>
-using namespace SPIRV;
-
-SPIRVFunctionParameter::SPIRVFunctionParameter(SPIRVType *TheType, SPIRVId TheId,
- SPIRVFunction *TheParent, unsigned TheArgNo):
- SPIRVValue(TheParent->getModule(), 3, OpFunctionParameter,
- TheType, TheId),
- ParentFunc(TheParent),
- ArgNo(TheArgNo){
- validate();
-}
-
-void
-SPIRVFunctionParameter::foreachAttr(
- std::function<void(SPIRVFuncParamAttrKind)>Func){
- auto Locs = Decorates.equal_range(DecorationFuncParamAttr);
- for (auto I = Locs.first, E = Locs.second; I != E; ++I){
- auto Attr = static_cast<SPIRVFuncParamAttrKind>(
- I->second->getLiteral(0));
- assert(isValid(Attr));
- Func(Attr);
- }
-}
-
-SPIRVDecoder
-SPIRVFunction::getDecoder(std::istream &IS) {
- return SPIRVDecoder(IS, *this);
-}
-
-void
-SPIRVFunction::encode(spv_ostream &O) const {
- getEncoder(O) << Type << Id << FCtrlMask << FuncType;
-}
-
-void
-SPIRVFunction::encodeChildren(spv_ostream &O) const {
- O << SPIRVNL();
- for (auto &I:Parameters)
- O << *I;
- O << SPIRVNL();
- for (auto &I:BBVec)
- O << *I;
- O << SPIRVFunctionEnd();
-}
-
-void
-SPIRVFunction::encodeExecutionModes(spv_ostream &O)const {
- for (auto &I:ExecModes)
- O << *I.second;
-}
-
-void
-SPIRVFunction::decode(std::istream &I) {
- SPIRVDecoder Decoder = getDecoder(I);
- Decoder >> Type >> Id >> FCtrlMask >> FuncType;
- Module->addFunction(this);
- SPIRVDBG(spvdbgs() << "Decode function: " << Id << '\n');
-
- Decoder.getWordCountAndOpCode();
- while (!I.eof()) {
- if (Decoder.OpCode == OpFunctionEnd)
- break;
-
- switch(Decoder.OpCode) {
- case OpFunctionParameter: {
- auto Param = static_cast<SPIRVFunctionParameter *>(Decoder.getEntry());
- assert(Param);
- Module->add(Param);
- Param->setParent(this);
- Parameters.push_back(Param);
- Decoder.getWordCountAndOpCode();
- continue;
- break;
- }
- case OpLabel: {
- decodeBB(Decoder);
- break;
- }
- default:
- assert (0 && "Invalid SPIRV format");
- }
- }
-}
-
-/// Decode basic block and contained instructions.
-/// Do it here instead of in BB:decode to avoid back track in input stream.
-void
-SPIRVFunction::decodeBB(SPIRVDecoder &Decoder) {
- SPIRVBasicBlock *BB = static_cast<SPIRVBasicBlock*>(Decoder.getEntry());
- assert(BB);
- addBasicBlock(BB);
- SPIRVDBG(spvdbgs() << "Decode BB: " << BB->getId() << '\n');
-
- Decoder.setScope(BB);
- while(Decoder.getWordCountAndOpCode()) {
- if (Decoder.OpCode == OpFunctionEnd ||
- Decoder.OpCode == OpLabel) {
- break;
- }
-
- if (Decoder.OpCode == OpLine) {
- Module->add(Decoder.getEntry());
- continue;
- }
-
- SPIRVInstruction *Inst = static_cast<SPIRVInstruction *>(Decoder.getEntry());
- assert(Inst);
- if (Inst->getOpCode() != OpUndef)
- BB->addInstruction(Inst);
- else
- Module->add(Inst);
- }
- Decoder.setScope(this);
-}
-
-void
-SPIRVFunction::foreachReturnValueAttr(
- std::function<void(SPIRVFuncParamAttrKind)>Func){
- auto Locs = Decorates.equal_range(DecorationFuncParamAttr);
- for (auto I = Locs.first, E = Locs.second; I != E; ++I){
- auto Attr = static_cast<SPIRVFuncParamAttrKind>(
- I->second->getLiteral(0));
- assert(isValid(Attr));
- Func(Attr);
- }
-}
+//===- SPIRVFunction.cpp - Class to represent a SPIR-V Function --*- C++ -*-===// +// +// The LLVM/SPIRV Translator +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Function class for SPIRV. +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "SPIRVEntry.h" +#include "SPIRVFunction.h" +#include "SPIRVBasicBlock.h" +#include "SPIRVInstruction.h" +#include "SPIRVStream.h" + +#include <functional> +#include <algorithm> +using namespace SPIRV; + +SPIRVFunctionParameter::SPIRVFunctionParameter(SPIRVType *TheType, SPIRVId TheId, + SPIRVFunction *TheParent, unsigned TheArgNo): + SPIRVValue(TheParent->getModule(), 3, OpFunctionParameter, + TheType, TheId), + ParentFunc(TheParent), + ArgNo(TheArgNo){ + validate(); +} + +void +SPIRVFunctionParameter::foreachAttr( + std::function<void(SPIRVFuncParamAttrKind)>Func){ + auto Locs = Decorates.equal_range(DecorationFuncParamAttr); + for (auto I = Locs.first, E = Locs.second; I != E; ++I){ + auto Attr = static_cast<SPIRVFuncParamAttrKind>( + I->second->getLiteral(0)); + assert(isValid(Attr)); + Func(Attr); + } +} + +SPIRVDecoder +SPIRVFunction::getDecoder(std::istream &IS) { + return SPIRVDecoder(IS, *this); +} + +void +SPIRVFunction::encode(spv_ostream &O) const { + getEncoder(O) << Type << Id << FCtrlMask << FuncType; +} + +void +SPIRVFunction::encodeChildren(spv_ostream &O) const { + O << SPIRVNL(); + for (auto &I:Parameters) + O << *I; + O << SPIRVNL(); + for (auto &I:BBVec) + O << *I; + O << SPIRVFunctionEnd(); +} + +void +SPIRVFunction::encodeExecutionModes(spv_ostream &O)const { + for (auto &I:ExecModes) + O << *I.second; +} + +void +SPIRVFunction::decode(std::istream &I) { + SPIRVDecoder Decoder = getDecoder(I); + Decoder >> Type >> Id >> FCtrlMask >> FuncType; + Module->addFunction(this); + SPIRVDBG(spvdbgs() << "Decode function: " << Id << '\n'); + + Decoder.getWordCountAndOpCode(); + while (!I.eof()) { + if (Decoder.OpCode == OpFunctionEnd) + break; + + switch(Decoder.OpCode) { + case OpFunctionParameter: { + auto Param = static_cast<SPIRVFunctionParameter *>(Decoder.getEntry()); + assert(Param); + Module->add(Param); + Param->setParent(this); + Parameters.push_back(Param); + Decoder.getWordCountAndOpCode(); + continue; + break; + } + case OpLabel: { + decodeBB(Decoder); + break; + } + default: + assert (0 && "Invalid SPIRV format"); + } + } +} + +/// Decode basic block and contained instructions. +/// Do it here instead of in BB:decode to avoid back track in input stream. +void +SPIRVFunction::decodeBB(SPIRVDecoder &Decoder) { + SPIRVBasicBlock *BB = static_cast<SPIRVBasicBlock*>(Decoder.getEntry()); + assert(BB); + addBasicBlock(BB); + SPIRVDBG(spvdbgs() << "Decode BB: " << BB->getId() << '\n'); + + Decoder.setScope(BB); + while(Decoder.getWordCountAndOpCode()) { + if (Decoder.OpCode == OpFunctionEnd || + Decoder.OpCode == OpLabel) { + break; + } + + if (Decoder.OpCode == OpLine) { + Module->add(Decoder.getEntry()); + continue; + } + + SPIRVInstruction *Inst = static_cast<SPIRVInstruction *>(Decoder.getEntry()); + assert(Inst); + if (Inst->getOpCode() != OpUndef) + BB->addInstruction(Inst); + else + Module->add(Inst); + } + Decoder.setScope(this); +} + +void +SPIRVFunction::foreachReturnValueAttr( + std::function<void(SPIRVFuncParamAttrKind)>Func){ + auto Locs = Decorates.equal_range(DecorationFuncParamAttr); + for (auto I = Locs.first, E = Locs.second; I != E; ++I){ + auto Attr = static_cast<SPIRVFuncParamAttrKind>( + I->second->getLiteral(0)); + assert(isValid(Attr)); + Func(Attr); + } +} diff --git a/lib/SPIRV/libSPIRV/SPIRVFunction.h b/lib/SPIRV/libSPIRV/SPIRVFunction.h index 060cab4..ff75f7a 100644 --- a/lib/SPIRV/libSPIRV/SPIRVFunction.h +++ b/lib/SPIRV/libSPIRV/SPIRVFunction.h @@ -1,168 +1,168 @@ -//===- SPIRVFunction.h - Class to represent a SPIR-V function ----*- C++ -*-===//
-//
-// The LLVM/SPIRV Translator
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines Function class for SPIRV.
-//
-// 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.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVFUNCTION_HPP_
-#define SPIRVFUNCTION_HPP_
-#include "SPIRVValue.h"
-#include "SPIRVBasicBlock.h"
-#include <functional>
-
-namespace SPIRV{
-
-class BIFunction;
-class SPIRVDecoder;
-
-class SPIRVFunctionParameter: public SPIRVValue {
-public:
- SPIRVFunctionParameter(SPIRVType *TheType, SPIRVId TheId,
- SPIRVFunction *TheParent, unsigned TheArgNo);
- SPIRVFunctionParameter():SPIRVValue(OpFunctionParameter),
- ParentFunc(nullptr), ArgNo(0){}
- unsigned getArgNo()const { return ArgNo;}
- void foreachAttr(std::function<void(SPIRVFuncParamAttrKind)>);
- void addAttr(SPIRVFuncParamAttrKind Kind) {
- addDecorate(new SPIRVDecorate(DecorationFuncParamAttr, this, Kind));
- }
- void setParent(SPIRVFunction *Parent) { ParentFunc = Parent;}
- bool hasAttr(SPIRVFuncParamAttrKind Kind) const {
- return getDecorate(DecorationFuncParamAttr).count(Kind) ;
- }
- bool isByVal()const { return hasAttr(FunctionParameterAttributeByVal);}
- bool isZext()const { return hasAttr(FunctionParameterAttributeZext);}
- SPIRVCapVec getRequiredCapability() const {
- if (hasLinkageType() && getLinkageType() == LinkageTypeImport)
- return getVec(CapabilityLinkage);
- return SPIRVCapVec();
- }
-protected:
- void validate()const {
- SPIRVValue::validate();
- assert(ParentFunc && "Invalid parent function");
- }
- _SPIRV_DEF_ENCDEC2(Type, Id)
-private:
- SPIRVFunction *ParentFunc;
- unsigned ArgNo;
-};
-
-class SPIRVFunction: public SPIRVValue, public SPIRVComponentExecutionModes {
-public:
- // Complete constructor. It does not construct basic blocks.
- SPIRVFunction(SPIRVModule *M, SPIRVTypeFunction *FunctionType, SPIRVId TheId)
- :SPIRVValue(M, 5, OpFunction, FunctionType->getReturnType(), TheId),
- FuncType(FunctionType), FCtrlMask(FunctionControlMaskNone) {
- addAllArguments(TheId + 1);
- validate();
- }
-
- // Incomplete constructor
- SPIRVFunction():SPIRVValue(OpFunction),FuncType(NULL),
- FCtrlMask(FunctionControlMaskNone){}
-
- SPIRVDecoder getDecoder(std::istream &IS);
- SPIRVTypeFunction *getFunctionType() const { return FuncType;}
- SPIRVWord getFuncCtlMask() const { return FCtrlMask;}
- size_t getNumBasicBlock() const { return BBVec.size();}
- SPIRVBasicBlock *getBasicBlock(size_t i) const { return BBVec[i];}
- size_t getNumArguments() const {
- return getFunctionType()->getNumParameters();
- }
- SPIRVId getArgumentId(size_t i)const { return Parameters[i]->getId();}
- SPIRVFunctionParameter *getArgument(size_t i) const {
- return Parameters[i];
- }
- void foreachArgument(std::function<void(SPIRVFunctionParameter *)>Func) {
- for (size_t I = 0, E = getNumArguments(); I != E; ++I)
- Func(getArgument(I));
- }
-
- void foreachReturnValueAttr(std::function<void(SPIRVFuncParamAttrKind)>);
-
- void setFunctionControlMask(SPIRVWord Mask) {
- FCtrlMask = Mask;
- }
-
- void takeExecutionModes(SPIRVForward *Forward) {
- ExecModes = std::move(Forward->ExecModes);
- }
-
- // Assume BB contains valid Id.
- SPIRVBasicBlock *addBasicBlock(SPIRVBasicBlock *BB) {
- Module->add(BB);
- BB->setParent(this);
- BBVec.push_back(BB);
- return BB;
- }
-
- void encodeChildren(spv_ostream &)const;
- void encodeExecutionModes(spv_ostream &)const;
- _SPIRV_DCL_ENCDEC
- void validate()const {
- SPIRVValue::validate();
- assert(FuncType && "Invalid func type");
- }
-
-private:
- SPIRVFunctionParameter *addArgument(unsigned TheArgNo, SPIRVId TheId) {
- SPIRVFunctionParameter *Arg = new SPIRVFunctionParameter(
- getFunctionType()->getParameterType(TheArgNo),
- TheId, this, TheArgNo);
- Module->add(Arg);
- Parameters.push_back(Arg);
- return Arg;
- }
-
- void addAllArguments(SPIRVId FirstArgId) {
- for (size_t i = 0, e = getFunctionType()->getNumParameters(); i != e; ++i)
- addArgument(i, FirstArgId + i);
- }
- void decodeBB(SPIRVDecoder &);
-
- SPIRVTypeFunction *FuncType; // Function type
- SPIRVWord FCtrlMask; // Function control mask
-
- std::vector<SPIRVFunctionParameter *> Parameters;
- typedef std::vector<SPIRVBasicBlock *> SPIRVLBasicBlockVector;
- SPIRVLBasicBlockVector BBVec;
-};
-
-typedef SPIRVEntryOpCodeOnly<OpFunctionEnd> SPIRVFunctionEnd;
-
-}
-
-#endif /* SPIRVFUNCTION_HPP_ */
+//===- SPIRVFunction.h - Class to represent a SPIR-V function ----*- C++ -*-===// +// +// The LLVM/SPIRV Translator +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines Function class for SPIRV. +// +// 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. +// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVFUNCTION_HPP_ +#define SPIRVFUNCTION_HPP_ +#include "SPIRVValue.h" +#include "SPIRVBasicBlock.h" +#include <functional> + +namespace SPIRV{ + +class BIFunction; +class SPIRVDecoder; + +class SPIRVFunctionParameter: public SPIRVValue { +public: + SPIRVFunctionParameter(SPIRVType *TheType, SPIRVId TheId, + SPIRVFunction *TheParent, unsigned TheArgNo); + SPIRVFunctionParameter():SPIRVValue(OpFunctionParameter), + ParentFunc(nullptr), ArgNo(0){} + unsigned getArgNo()const { return ArgNo;} + void foreachAttr(std::function<void(SPIRVFuncParamAttrKind)>); + void addAttr(SPIRVFuncParamAttrKind Kind) { + addDecorate(new SPIRVDecorate(DecorationFuncParamAttr, this, Kind)); + } + void setParent(SPIRVFunction *Parent) { ParentFunc = Parent;} + bool hasAttr(SPIRVFuncParamAttrKind Kind) const { + return getDecorate(DecorationFuncParamAttr).count(Kind) ; + } + bool isByVal()const { return hasAttr(FunctionParameterAttributeByVal);} + bool isZext()const { return hasAttr(FunctionParameterAttributeZext);} + SPIRVCapVec getRequiredCapability() const { + if (hasLinkageType() && getLinkageType() == LinkageTypeImport) + return getVec(CapabilityLinkage); + return SPIRVCapVec(); + } +protected: + void validate()const { + SPIRVValue::validate(); + assert(ParentFunc && "Invalid parent function"); + } + _SPIRV_DEF_ENCDEC2(Type, Id) +private: + SPIRVFunction *ParentFunc; + unsigned ArgNo; +}; + +class SPIRVFunction: public SPIRVValue, public SPIRVComponentExecutionModes { +public: + // Complete constructor. It does not construct basic blocks. + SPIRVFunction(SPIRVModule *M, SPIRVTypeFunction *FunctionType, SPIRVId TheId) + :SPIRVValue(M, 5, OpFunction, FunctionType->getReturnType(), TheId), + FuncType(FunctionType), FCtrlMask(FunctionControlMaskNone) { + addAllArguments(TheId + 1); + validate(); + } + + // Incomplete constructor + SPIRVFunction():SPIRVValue(OpFunction),FuncType(NULL), + FCtrlMask(FunctionControlMaskNone){} + + SPIRVDecoder getDecoder(std::istream &IS); + SPIRVTypeFunction *getFunctionType() const { return FuncType;} + SPIRVWord getFuncCtlMask() const { return FCtrlMask;} + size_t getNumBasicBlock() const { return BBVec.size();} + SPIRVBasicBlock *getBasicBlock(size_t i) const { return BBVec[i];} + size_t getNumArguments() const { + return getFunctionType()->getNumParameters(); + } + SPIRVId getArgumentId(size_t i)const { return Parameters[i]->getId();} + SPIRVFunctionParameter *getArgument(size_t i) const { + return Parameters[i]; + } + void foreachArgument(std::function<void(SPIRVFunctionParameter *)>Func) { + for (size_t I = 0, E = getNumArguments(); I != E; ++I) + Func(getArgument(I)); + } + + void foreachReturnValueAttr(std::function<void(SPIRVFuncParamAttrKind)>); + + void setFunctionControlMask(SPIRVWord Mask) { + FCtrlMask = Mask; + } + + void takeExecutionModes(SPIRVForward *Forward) { + ExecModes = std::move(Forward->ExecModes); + } + + // Assume BB contains valid Id. + SPIRVBasicBlock *addBasicBlock(SPIRVBasicBlock *BB) { + Module->add(BB); + BB->setParent(this); + BBVec.push_back(BB); + return BB; + } + + void encodeChildren(spv_ostream &)const; + void encodeExecutionModes(spv_ostream &)const; + _SPIRV_DCL_ENCDEC + void validate()const { + SPIRVValue::validate(); + assert(FuncType && "Invalid func type"); + } + +private: + SPIRVFunctionParameter *addArgument(unsigned TheArgNo, SPIRVId TheId) { + SPIRVFunctionParameter *Arg = new SPIRVFunctionParameter( + getFunctionType()->getParameterType(TheArgNo), + TheId, this, TheArgNo); + Module->add(Arg); + Parameters.push_back(Arg); + return Arg; + } + + void addAllArguments(SPIRVId FirstArgId) { + for (size_t i = 0, e = getFunctionType()->getNumParameters(); i != e; ++i) + addArgument(i, FirstArgId + i); + } + void decodeBB(SPIRVDecoder &); + + SPIRVTypeFunction *FuncType; // Function type + SPIRVWord FCtrlMask; // Function control mask + + std::vector<SPIRVFunctionParameter *> Parameters; + typedef std::vector<SPIRVBasicBlock *> SPIRVLBasicBlockVector; + SPIRVLBasicBlockVector BBVec; +}; + +typedef SPIRVEntryOpCodeOnly<OpFunctionEnd> SPIRVFunctionEnd; + +} + +#endif /* SPIRVFUNCTION_HPP_ */ diff --git a/lib/SPIRV/libSPIRV/SPIRVInstruction.cpp b/lib/SPIRV/libSPIRV/SPIRVInstruction.cpp index b30de26..774a444 100644 --- a/lib/SPIRV/libSPIRV/SPIRVInstruction.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVInstruction.cpp @@ -1,232 +1,232 @@ -//===- SPIRVInstruction.cpp -Class to represent SPIR-V instruction - 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file implements SPIR-V instructions.
-///
-//===----------------------------------------------------------------------===//
-
-#include "SPIRVInstruction.h"
-#include "SPIRVBasicBlock.h"
-#include "SPIRVFunction.h"
-
-#include <unordered_set>
-
-namespace SPIRV {
-
-// Complete constructor for instruction with type and id
-SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
- SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB)
- :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheType, TheId),
- BB(TheBB){
- validate();
-}
-
-SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
- SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB, SPIRVModule *TheBM)
- : SPIRVValue(TheBM, TheWordCount, TheOC, TheType, TheId), BB(TheBB){
- validate();
-}
-
-// Complete constructor for instruction with id but no type
-SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
- SPIRVId TheId, SPIRVBasicBlock *TheBB)
- :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheId), BB(TheBB){
- validate();
-}
-// Complete constructor for instruction without type and id
-SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
- SPIRVBasicBlock *TheBB)
- :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC), BB(TheBB){
- validate();
-}
-// Complete constructor for instruction with type but no id
-SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
- SPIRVType *TheType, SPIRVBasicBlock *TheBB)
- :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheType), BB(TheBB){
- validate();
-}
-
-void
-SPIRVInstruction::setParent(SPIRVBasicBlock *TheBB) {
- assert(TheBB && "Invalid BB");
- if (BB == TheBB)
- return;
- assert(BB == NULL && "BB cannot change parent");
- BB = TheBB;
-}
-
-void
-SPIRVInstruction::setScope(SPIRVEntry *Scope) {
- assert(Scope && Scope->getOpCode() == OpLabel && "Invalid scope");
- setParent(static_cast<SPIRVBasicBlock*>(Scope));
-}
-
-SPIRVFunctionCall::SPIRVFunctionCall(SPIRVId TheId, SPIRVFunction *TheFunction,
- const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB)
- :SPIRVFunctionCallGeneric(
- TheFunction->getFunctionType()->getReturnType(),
- TheId, TheArgs, BB), FunctionId(TheFunction->getId()){
- validate();
-}
-
-void
-SPIRVFunctionCall::validate()const {
- SPIRVFunctionCallGeneric::validate();
-}
-
-// ToDo: Each instruction should implement this function
-std::vector<SPIRVValue *>
-SPIRVInstruction::getOperands() {
- std::vector<SPIRVValue *> Empty;
- assert(0 && "not supported");
- return Empty;
-}
-
-std::vector<SPIRVType*>
-SPIRVInstruction::getOperandTypes(const std::vector<SPIRVValue *> &Ops) {
- std::vector<SPIRVType*> Tys;
- for (auto& I : Ops) {
- SPIRVType* Ty = nullptr;
- if (I->getOpCode() == OpFunction)
- Ty = reinterpret_cast<SPIRVFunction*>(I)->getFunctionType();
- else
- Ty = I->getType();
-
- Tys.push_back(Ty);
- }
- return Tys;
-}
-
-std::vector<SPIRVType*>
-SPIRVInstruction::getOperandTypes() {
- return getOperandTypes(getOperands());
-}
-
-bool
-isSpecConstantOpAllowedOp(Op OC) {
- static SPIRVWord Table[] =
- {
- OpSConvert,
- OpFConvert,
- OpConvertFToS,
- OpConvertSToF,
- OpConvertFToU,
- OpConvertUToF,
- OpUConvert,
- OpConvertPtrToU,
- OpConvertUToPtr,
- OpGenericCastToPtr,
- OpPtrCastToGeneric,
- OpBitcast,
- OpQuantizeToF16,
- OpSNegate,
- OpNot,
- OpIAdd,
- OpISub,
- OpIMul,
- OpUDiv,
- OpSDiv,
- OpUMod,
- OpSRem,
- OpSMod,
- OpShiftRightLogical,
- OpShiftRightArithmetic,
- OpShiftLeftLogical,
- OpBitwiseOr,
- OpBitwiseXor,
- OpBitwiseAnd,
- OpFNegate,
- OpFAdd,
- OpFSub,
- OpFMul,
- OpFDiv,
- OpFRem,
- OpFMod,
- OpVectorShuffle,
- OpCompositeExtract,
- OpCompositeInsert,
- OpLogicalOr,
- OpLogicalAnd,
- OpLogicalNot,
- OpLogicalEqual,
- OpLogicalNotEqual,
- OpSelect,
- OpIEqual,
- OpULessThan,
- OpSLessThan,
- OpUGreaterThan,
- OpSGreaterThan,
- OpULessThanEqual,
- OpSLessThanEqual,
- OpUGreaterThanEqual,
- OpSGreaterThanEqual,
- OpAccessChain,
- OpInBoundsAccessChain,
- OpPtrAccessChain,
- OpInBoundsPtrAccessChain,
- };
- static std::unordered_set<SPIRVWord>
- Allow(std::begin(Table), std::end(Table));
- return Allow.count(OC);
-}
-
-SPIRVSpecConstantOp *
-createSpecConstantOpInst(SPIRVInstruction *Inst) {
- auto OC = Inst->getOpCode();
- assert (isSpecConstantOpAllowedOp(OC) &&
- "Op code not allowed for OpSpecConstantOp");
- auto Ops = Inst->getIds(Inst->getOperands());
- Ops.insert(Ops.begin(), OC);
- return static_cast<SPIRVSpecConstantOp *>(
- SPIRVSpecConstantOp::create(OpSpecConstantOp, Inst->getType(),
- Inst->getId(), Ops, nullptr, Inst->getModule()));
-}
-
-SPIRVInstruction *
-createInstFromSpecConstantOp(SPIRVSpecConstantOp *Inst) {
- assert(Inst->getOpCode() == OpSpecConstantOp &&
- "Not OpSpecConstantOp");
- auto Ops = Inst->getOpWords();
- auto OC = static_cast<Op>(Ops[0]);
- assert (isSpecConstantOpAllowedOp(OC) &&
- "Op code not allowed for OpSpecConstantOp");
- Ops.erase(Ops.begin(), Ops.begin() + 1);
- return SPIRVInstTemplateBase::create(OC, Inst->getType(),
- Inst->getId(), Ops, nullptr, Inst->getModule());
-}
-
-}
-
-
+//===- SPIRVInstruction.cpp -Class to represent SPIR-V instruction - 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file implements SPIR-V instructions. +/// +//===----------------------------------------------------------------------===// + +#include "SPIRVInstruction.h" +#include "SPIRVBasicBlock.h" +#include "SPIRVFunction.h" + +#include <unordered_set> + +namespace SPIRV { + +// Complete constructor for instruction with type and id +SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, + SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB) + :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheType, TheId), + BB(TheBB){ + validate(); +} + +SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, + SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB, SPIRVModule *TheBM) + : SPIRVValue(TheBM, TheWordCount, TheOC, TheType, TheId), BB(TheBB){ + validate(); +} + +// Complete constructor for instruction with id but no type +SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, + SPIRVId TheId, SPIRVBasicBlock *TheBB) + :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheId), BB(TheBB){ + validate(); +} +// Complete constructor for instruction without type and id +SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, + SPIRVBasicBlock *TheBB) + :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC), BB(TheBB){ + validate(); +} +// Complete constructor for instruction with type but no id +SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, + SPIRVType *TheType, SPIRVBasicBlock *TheBB) + :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheType), BB(TheBB){ + validate(); +} + +void +SPIRVInstruction::setParent(SPIRVBasicBlock *TheBB) { + assert(TheBB && "Invalid BB"); + if (BB == TheBB) + return; + assert(BB == NULL && "BB cannot change parent"); + BB = TheBB; +} + +void +SPIRVInstruction::setScope(SPIRVEntry *Scope) { + assert(Scope && Scope->getOpCode() == OpLabel && "Invalid scope"); + setParent(static_cast<SPIRVBasicBlock*>(Scope)); +} + +SPIRVFunctionCall::SPIRVFunctionCall(SPIRVId TheId, SPIRVFunction *TheFunction, + const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB) + :SPIRVFunctionCallGeneric( + TheFunction->getFunctionType()->getReturnType(), + TheId, TheArgs, BB), FunctionId(TheFunction->getId()){ + validate(); +} + +void +SPIRVFunctionCall::validate()const { + SPIRVFunctionCallGeneric::validate(); +} + +// ToDo: Each instruction should implement this function +std::vector<SPIRVValue *> +SPIRVInstruction::getOperands() { + std::vector<SPIRVValue *> Empty; + assert(0 && "not supported"); + return Empty; +} + +std::vector<SPIRVType*> +SPIRVInstruction::getOperandTypes(const std::vector<SPIRVValue *> &Ops) { + std::vector<SPIRVType*> Tys; + for (auto& I : Ops) { + SPIRVType* Ty = nullptr; + if (I->getOpCode() == OpFunction) + Ty = reinterpret_cast<SPIRVFunction*>(I)->getFunctionType(); + else + Ty = I->getType(); + + Tys.push_back(Ty); + } + return Tys; +} + +std::vector<SPIRVType*> +SPIRVInstruction::getOperandTypes() { + return getOperandTypes(getOperands()); +} + +bool +isSpecConstantOpAllowedOp(Op OC) { + static SPIRVWord Table[] = + { + OpSConvert, + OpFConvert, + OpConvertFToS, + OpConvertSToF, + OpConvertFToU, + OpConvertUToF, + OpUConvert, + OpConvertPtrToU, + OpConvertUToPtr, + OpGenericCastToPtr, + OpPtrCastToGeneric, + OpBitcast, + OpQuantizeToF16, + OpSNegate, + OpNot, + OpIAdd, + OpISub, + OpIMul, + OpUDiv, + OpSDiv, + OpUMod, + OpSRem, + OpSMod, + OpShiftRightLogical, + OpShiftRightArithmetic, + OpShiftLeftLogical, + OpBitwiseOr, + OpBitwiseXor, + OpBitwiseAnd, + OpFNegate, + OpFAdd, + OpFSub, + OpFMul, + OpFDiv, + OpFRem, + OpFMod, + OpVectorShuffle, + OpCompositeExtract, + OpCompositeInsert, + OpLogicalOr, + OpLogicalAnd, + OpLogicalNot, + OpLogicalEqual, + OpLogicalNotEqual, + OpSelect, + OpIEqual, + OpULessThan, + OpSLessThan, + OpUGreaterThan, + OpSGreaterThan, + OpULessThanEqual, + OpSLessThanEqual, + OpUGreaterThanEqual, + OpSGreaterThanEqual, + OpAccessChain, + OpInBoundsAccessChain, + OpPtrAccessChain, + OpInBoundsPtrAccessChain, + }; + static std::unordered_set<SPIRVWord> + Allow(std::begin(Table), std::end(Table)); + return Allow.count(OC); +} + +SPIRVSpecConstantOp * +createSpecConstantOpInst(SPIRVInstruction *Inst) { + auto OC = Inst->getOpCode(); + assert (isSpecConstantOpAllowedOp(OC) && + "Op code not allowed for OpSpecConstantOp"); + auto Ops = Inst->getIds(Inst->getOperands()); + Ops.insert(Ops.begin(), OC); + return static_cast<SPIRVSpecConstantOp *>( + SPIRVSpecConstantOp::create(OpSpecConstantOp, Inst->getType(), + Inst->getId(), Ops, nullptr, Inst->getModule())); +} + +SPIRVInstruction * +createInstFromSpecConstantOp(SPIRVSpecConstantOp *Inst) { + assert(Inst->getOpCode() == OpSpecConstantOp && + "Not OpSpecConstantOp"); + auto Ops = Inst->getOpWords(); + auto OC = static_cast<Op>(Ops[0]); + assert (isSpecConstantOpAllowedOp(OC) && + "Op code not allowed for OpSpecConstantOp"); + Ops.erase(Ops.begin(), Ops.begin() + 1); + return SPIRVInstTemplateBase::create(OC, Inst->getType(), + Inst->getId(), Ops, nullptr, Inst->getModule()); +} + +} + + diff --git a/lib/SPIRV/libSPIRV/SPIRVInstruction.h b/lib/SPIRV/libSPIRV/SPIRVInstruction.h index b82cb4a..f01e052 100644 --- a/lib/SPIRV/libSPIRV/SPIRVInstruction.h +++ b/lib/SPIRV/libSPIRV/SPIRVInstruction.h @@ -1,2194 +1,2194 @@ -//===- SPIRVInstruction.h - Class to represent SPIRV instruction -*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines Instruction class for SPIR-V.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVINSTRUCTION_HPP_
-#define SPIRVINSTRUCTION_HPP_
-
-#include "SPIRVEnum.h"
-#include "SPIRVIsValidEnum.h"
-#include "SPIRVStream.h"
-#include "SPIRVValue.h"
-#include "SPIRVBasicBlock.h"
-#include "SPIRVOpCode.h"
-
-#include <cassert>
-#include <cstdint>
-#include <functional>
-#include <iostream>
-#include <map>
-#include <utility>
-#include <vector>
-#include <unordered_set>
-
-namespace SPIRV{
-
-typedef std::vector<SPIRVValue *> ValueVec;
-typedef std::pair<ValueVec::iterator, ValueVec::iterator> ValueRange;
-
-class SPIRVBasicBlock;
-class SPIRVFunction;
-
-bool isSpecConstantOpAllowedOp(Op OC);
-
-class SPIRVComponentExecutionScope {
-public:
- SPIRVComponentExecutionScope(Scope TheScope = ScopeInvocation):
- ExecScope(TheScope){}
- Scope ExecScope;
-};
-
-class SPIRVComponentMemorySemanticsMask {
-public:
- SPIRVComponentMemorySemanticsMask(SPIRVWord TheSema = SPIRVWORD_MAX):
- MemSema(TheSema){}
- SPIRVWord MemSema;
-};
-
-class SPIRVComponentOperands {
-public:
- SPIRVComponentOperands(){};
- SPIRVComponentOperands(const std::vector<SPIRVValue *> &TheOperands):
- Operands(TheOperands){};
- SPIRVComponentOperands(std::vector<SPIRVValue *> &&TheOperands):
- Operands(std::move(TheOperands)){};
- std::vector<SPIRVValue *> getCompOperands() {
- return Operands;
- }
- std::vector<SPIRVType *> getCompOperandTypes() {
- std::vector<SPIRVType *> Tys;
- for (auto &I:getCompOperands())
- Tys.push_back(I->getType());
- return Tys;
- }
-protected:
- std::vector<SPIRVValue *> Operands;
-};
-
-class SPIRVInstruction: public SPIRVValue {
-public:
- // Complete constructor for instruction with type and id
- SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType,
- SPIRVId TheId, SPIRVBasicBlock *TheBB);
- // Complete constructor for instruction with module, type and id
- SPIRVInstruction(unsigned TheWordCount, Op TheOC,
- SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB,
- SPIRVModule *TheBM);
- // Complete constructor for instruction with id but no type
- SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVId TheId,
- SPIRVBasicBlock *TheBB);
- // Complete constructor for instruction without type and id
- SPIRVInstruction(unsigned TheWordCount, Op TheOC,
- SPIRVBasicBlock *TheBB);
- // Complete constructor for instruction with type but no id
- SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType,
- SPIRVBasicBlock *TheBB);
- // Incomplete constructor
- SPIRVInstruction(Op TheOC = OpNop):SPIRVValue(TheOC), BB(NULL){}
-
- virtual bool isInst() const { return true;}
- SPIRVBasicBlock *getParent() const {return BB;}
- SPIRVInstruction *getPrevious() const { return BB->getPrevious(this);}
- SPIRVInstruction *getNext() const { return BB->getNext(this);}
- virtual std::vector<SPIRVValue *> getOperands();
- std::vector<SPIRVType*> getOperandTypes();
- static std::vector<SPIRVType*> getOperandTypes(
- const std::vector<SPIRVValue *> &Ops);
-
- void setParent(SPIRVBasicBlock *);
- void setScope(SPIRVEntry *);
- void addFPRoundingMode(SPIRVFPRoundingModeKind Kind) {
- addDecorate(DecorationFPRoundingMode, Kind);
- }
- void eraseFPRoundingMode() {
- eraseDecorate(DecorationFPRoundingMode);
- }
- void setSaturatedConversion(bool Enable) {
- if (Enable)
- addDecorate(DecorationSaturatedConversion);
- else
- eraseDecorate(DecorationSaturatedConversion);
- }
- bool hasFPRoundingMode(SPIRVFPRoundingModeKind *Kind = nullptr) {
- SPIRVWord V;
- auto Found = hasDecorate(DecorationFPRoundingMode, 0, &V);
- if (Found && Kind)
- *Kind = static_cast<SPIRVFPRoundingModeKind>(V);
- return Found;
- }
- bool isSaturatedConversion() {
- return hasDecorate(DecorationSaturatedConversion) ||
- OpCode == OpSatConvertSToU ||
- OpCode == OpSatConvertUToS;
- }
-
- SPIRVBasicBlock* getBasicBlock() const {
- return BB;
- }
-
- void setBasicBlock(SPIRVBasicBlock* TheBB) {
- BB = TheBB;
- if (TheBB)
- setModule(TheBB->getModule());
- }
-
-protected:
- void validate()const {
- SPIRVValue::validate();
- }
-private:
- SPIRVBasicBlock *BB;
-};
-
-class SPIRVInstTemplateBase:public SPIRVInstruction {
-public:
- /// Create an empty instruction. Mainly for getting format information,
- /// e.g. whether an operand is literal.
- static SPIRVInstTemplateBase *create(Op TheOC){
- auto Inst = static_cast<SPIRVInstTemplateBase *>(SPIRVEntry::create(TheOC));
- assert(Inst);
- Inst->init();
- return Inst;
- }
- /// Create a instruction without operands.
- static SPIRVInstTemplateBase *create(Op TheOC, SPIRVType *TheType,
- SPIRVId TheId, SPIRVBasicBlock *TheBB,
- SPIRVModule *TheModule){
- auto Inst = create(TheOC);
- Inst->init(TheType, TheId, TheBB, TheModule);
- return Inst;
- }
- /// Create a complete and valid instruction.
- static SPIRVInstTemplateBase *create(Op TheOC, SPIRVType *TheType,
- SPIRVId TheId, const std::vector<SPIRVWord> &TheOps, SPIRVBasicBlock *TheBB,
- SPIRVModule *TheModule){
- auto Inst = create(TheOC);
- Inst->init(TheType, TheId, TheBB, TheModule);
- Inst->setOpWords(TheOps);
- Inst->validate();
- return Inst;
- }
- SPIRVInstTemplateBase(Op OC = OpNop)
- :SPIRVInstruction(OC), HasVariWC(false){
- init();
- }
- virtual ~SPIRVInstTemplateBase(){}
- SPIRVInstTemplateBase *init(SPIRVType *TheType,
- SPIRVId TheId, SPIRVBasicBlock *TheBB,
- SPIRVModule *TheModule){
- assert((TheBB || TheModule) && "Invalid BB or Module");
- if (TheBB)
- setBasicBlock(TheBB);
- else {
- setModule(TheModule);
- }
- setId(hasId() ? TheId : SPIRVID_INVALID);
- setType(hasType() ? TheType : nullptr);
- return this;
- }
- virtual void init() {}
- virtual void initImpl(Op OC, bool HasId = true, SPIRVWord WC = 0,
- bool VariWC = false, unsigned Lit1 = ~0U,
- unsigned Lit2 = ~0U, unsigned Lit3 = ~0U){
- OpCode = OC;
- if (!HasId) {
- setHasNoId();
- setHasNoType();
- }
- if (WC)
- SPIRVEntry::setWordCount(WC);
- setHasVariableWordCount(VariWC);
- addLit(Lit1);
- addLit(Lit2);
- addLit(Lit3);
- }
- virtual bool isOperandLiteral(unsigned I) const {
- return Lit.count(I);
- }
- void addLit(unsigned L) {
- if (L != ~0U)
- Lit.insert(L);
- }
- /// \return Expected number of operands. If the instruction has variable
- /// number of words, return the minimum.
- SPIRVWord getExpectedNumOperands() const {
- assert(WordCount > 0 && "Word count not initialized");
- auto Exp = WordCount - 1;
- if (hasId())
- --Exp;
- if (hasType())
- --Exp;
- return Exp;
- }
- virtual void setOpWordsAndValidate(const std::vector<SPIRVWord> &TheOps) {
- setOpWords(TheOps);
- validate();
- }
- virtual void setOpWords(const std::vector<SPIRVWord> &TheOps) {
- SPIRVWord WC = TheOps.size() + 1;
- if (hasId())
- ++WC;
- if (hasType())
- ++WC;
- if (WordCount) {
- if (WordCount == WC) {
- // do nothing
- } else {
- assert(HasVariWC && WC >= WordCount && "Invalid word count");
- SPIRVEntry::setWordCount(WC);
- }
- } else
- SPIRVEntry::setWordCount(WC);
- Ops = TheOps;
- }
- virtual void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- auto NumOps = WordCount - 1;
- if (hasId())
- --NumOps;
- if (hasType())
- --NumOps;
- Ops.resize(NumOps);
- }
-
- std::vector<SPIRVWord> &getOpWords() {
- return Ops;
- }
-
- const std::vector<SPIRVWord> &getOpWords() const {
- return Ops;
- }
-
- SPIRVWord getOpWord(int I) const {
- return Ops[I];
- }
-
- /// Get operand as value.
- /// If the operand is a literal, return it as a uint32 constant.
- SPIRVValue *getOpValue(int I) {
- return isOperandLiteral(I) ? Module->getLiteralAsConstant(Ops[I]) :
- getValue(Ops[I]);
- }
-
- // Get the offset of operands.
- // Some instructions skip literals when returning operands.
- size_t getOperandOffset() const {
- if (hasExecScope() && !isGroupOpCode(OpCode) && !isPipeOpCode(OpCode))
- return 1;
- return 0;
- }
-
- // Get operands which are values.
- // Drop execution scope and group operation literals.
- // Return other literals as uint32 constants.
- virtual std::vector<SPIRVValue *> getOperands() {
- std::vector<SPIRVValue*> VOps;
- auto Offset = getOperandOffset();
- for (size_t I = 0, E = Ops.size() - Offset; I != E; ++I)
- VOps.push_back(getOperand(I));
- return VOps;
- }
-
- virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const {
- std::vector<SPIRVEntry*> Operands;
- for (size_t I = getOperandOffset(), E = Ops.size(); I < E; ++I)
- if (!isOperandLiteral(I))
- Operands.push_back(getEntry(Ops[I]));
- return Operands;
- }
-
- virtual SPIRVValue *getOperand(unsigned I) {
- return getOpValue(I + getOperandOffset());
- }
-
- bool hasExecScope() const {
- return SPIRV::hasExecScope(OpCode);
- }
-
- bool hasGroupOperation() const {
- return SPIRV::hasGroupOperation(OpCode);
- }
-
- bool getSPIRVGroupOperation(SPIRVGroupOperationKind &GroupOp) const {
- if (!hasGroupOperation())
- return false;
- GroupOp = static_cast<SPIRVGroupOperationKind>(Ops[1]);
- return true;
- }
-
- Scope getExecutionScope() const {
- if(!hasExecScope())
- return ScopeInvocation;
- return static_cast<Scope>(
- static_cast<SPIRVConstant*>(getValue(Ops[0]))->getZExtIntValue());
- }
-
- bool hasVariableWordCount() const {
- return HasVariWC;
- }
-
- void setHasVariableWordCount(bool VariWC) {
- HasVariWC = VariWC;
- }
-
-protected:
- virtual void encode(spv_ostream &O) const {
- auto E = getEncoder(O);
- if (hasType())
- E << Type;
- if (hasId())
- E << Id;
- E << Ops;
- }
- virtual void decode(std::istream &I) {
- auto D = getDecoder(I);
- if (hasType())
- D >> Type;
- if (hasId())
- D >> Id;
- D >> Ops;
- }
- std::vector<SPIRVWord> Ops;
- bool HasVariWC;
- std::unordered_set<unsigned> Lit; // Literal operand index
-};
-
-template<typename BT = SPIRVInstTemplateBase,
- Op OC = OpNop,
- bool HasId = true,
- SPIRVWord WC = 0,
- bool HasVariableWC = false,
- unsigned Literal1 = ~0U,
- unsigned Literal2 = ~0U,
- unsigned Literal3 = ~0U>
-class SPIRVInstTemplate:public BT {
-public:
- typedef BT BaseTy;
- SPIRVInstTemplate(){
- init();
- }
- virtual ~SPIRVInstTemplate(){}
- virtual void init() {
- this->initImpl(OC, HasId, WC, HasVariableWC, Literal1, Literal2, Literal3);
- }
-};
-
-class SPIRVMemoryAccess {
-public:
- SPIRVMemoryAccess(const std::vector<SPIRVWord> &TheMemoryAccess):
- TheMemoryAccessMask(0), Alignment(0) {
- MemoryAccessUpdate(TheMemoryAccess);
- }
-
- SPIRVMemoryAccess() : TheMemoryAccessMask(0), Alignment(0){}
-
- void MemoryAccessUpdate(const std::vector<SPIRVWord> &MemoryAccess) {
- if (!MemoryAccess.size())
- return;
- assert((MemoryAccess.size() == 1 || MemoryAccess.size() == 2) && "Invalid memory access operand size");
- TheMemoryAccessMask = MemoryAccess[0];
- if (MemoryAccess[0] & MemoryAccessAlignedMask) {
- assert(MemoryAccess.size() == 2 && "Alignment operand is missing");
- Alignment = MemoryAccess[1];
- }
- }
- SPIRVWord isVolatile() const { return getMemoryAccessMask() & MemoryAccessVolatileMask; }
- SPIRVWord isNonTemporal() const { return getMemoryAccessMask() & MemoryAccessNontemporalMask; }
- SPIRVWord getMemoryAccessMask() const { return TheMemoryAccessMask; }
- SPIRVWord getAlignment() const { return Alignment; }
-
-protected:
- SPIRVWord TheMemoryAccessMask;
- SPIRVWord Alignment;
-};
-
-class SPIRVVariable : public SPIRVInstruction {
-public:
- // Complete constructor for integer constant
- SPIRVVariable(SPIRVType *TheType, SPIRVId TheId,
- SPIRVValue *TheInitializer, const std::string &TheName,
- SPIRVStorageClassKind TheStorageClass, SPIRVBasicBlock *TheBB,
- SPIRVModule *TheM)
- :SPIRVInstruction(TheInitializer ? 5 : 4, OpVariable, TheType,
- TheId, TheBB, TheM),
- StorageClass(TheStorageClass){
- if (TheInitializer)
- Initializer.push_back(TheInitializer->getId());
- Name = TheName;
- validate();
- }
- // Incomplete constructor
- SPIRVVariable() :SPIRVInstruction(OpVariable),
- StorageClass(StorageClassFunction){}
-
- SPIRVStorageClassKind getStorageClass() const { return StorageClass; }
- SPIRVValue *getInitializer() const {
- if (Initializer.empty())
- return nullptr;
- assert(Initializer.size() == 1);
- return getValue(Initializer[0]);
- }
- bool isConstant() const {
- return hasDecorate(DecorationConstant);
- }
- bool isBuiltin(SPIRVBuiltinVariableKind *BuiltinKind = nullptr) const {
- SPIRVWord Kind;
- bool Found = hasDecorate(DecorationBuiltIn, 0, &Kind);
- if (!Found)
- return false;
- if (BuiltinKind)
- *BuiltinKind = static_cast<SPIRVBuiltinVariableKind>(Kind);
- return true;
- }
- void setBuiltin(SPIRVBuiltinVariableKind Kind) {
- assert(isValid(Kind));
- addDecorate(new SPIRVDecorate(DecorationBuiltIn, this, Kind));
- }
- void setIsConstant(bool Is) {
- if (Is)
- addDecorate(new SPIRVDecorate(DecorationConstant, this));
- else
- eraseDecorate(DecorationConstant);
- }
- virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const {
- if (SPIRVValue *V = getInitializer())
- return std::vector<SPIRVEntry*>(1, V);
- return std::vector<SPIRVEntry*>();
- }
-protected:
- void validate() const {
- SPIRVValue::validate();
- assert(isValid(StorageClass));
- assert(Initializer.size() == 1 || Initializer.empty());
- assert(getType()->isTypePointer());
- }
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- Initializer.resize(WordCount - 4);
- }
- _SPIRV_DEF_ENCDEC4(Type, Id, StorageClass, Initializer)
-
- SPIRVStorageClassKind StorageClass;
- std::vector<SPIRVId> Initializer;
-};
-
-class SPIRVStore:public SPIRVInstruction, public SPIRVMemoryAccess {
-public:
- const static SPIRVWord FixedWords = 3;
- // Complete constructor
- SPIRVStore(SPIRVId PointerId, SPIRVId ValueId,
- const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *TheBB)
- :SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OpStore,
- TheBB),
- SPIRVMemoryAccess(TheMemoryAccess),
- MemoryAccess(TheMemoryAccess),
- PtrId(PointerId),
- ValId(ValueId){
- setAttr();
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVStore():SPIRVInstruction(OpStore), SPIRVMemoryAccess(),
- PtrId(SPIRVID_INVALID), ValId(SPIRVID_INVALID){
- setAttr();
- }
-
- SPIRVValue *getSrc() const { return getValue(ValId);}
- SPIRVValue *getDst() const { return getValue(PtrId);}
-protected:
- void setAttr() {
- setHasNoType();
- setHasNoId();
- }
-
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- MemoryAccess.resize(TheWordCount - FixedWords);
- }
- void encode(spv_ostream &O) const {
- getEncoder(O) << PtrId << ValId << MemoryAccess;
- }
-
- void decode(std::istream &I) {
- getDecoder(I) >> PtrId >> ValId >> MemoryAccess;
- MemoryAccessUpdate(MemoryAccess);
- }
-
- void validate()const {
- SPIRVInstruction::validate();
- if (getSrc()->isForward() || getDst()->isForward())
- return;
- assert(getValueType(PtrId)->getPointerElementType() == getValueType(ValId)
- && "Inconsistent operand types");
- }
-private:
- std::vector<SPIRVWord> MemoryAccess;
- SPIRVId PtrId;
- SPIRVId ValId;
-};
-
-class SPIRVLoad:public SPIRVInstruction, public SPIRVMemoryAccess {
-public:
- const static SPIRVWord FixedWords = 4;
- // Complete constructor
- SPIRVLoad(SPIRVId TheId, SPIRVId PointerId,
- const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *TheBB)
- :SPIRVInstruction(FixedWords + TheMemoryAccess.size() , OpLoad,
- TheBB->getValueType(PointerId)->getPointerElementType(), TheId, TheBB),
- SPIRVMemoryAccess(TheMemoryAccess), PtrId(PointerId),
- MemoryAccess(TheMemoryAccess) {
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVLoad():SPIRVInstruction(OpLoad), SPIRVMemoryAccess(),
- PtrId(SPIRVID_INVALID){}
-
- SPIRVValue *getSrc() const { return Module->get<SPIRVValue>(PtrId);}
-
-protected:
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- MemoryAccess.resize(TheWordCount - FixedWords);
- }
-
- void encode(spv_ostream &O) const {
- getEncoder(O) << Type << Id << PtrId << MemoryAccess;
- }
-
- void decode(std::istream &I) {
- getDecoder(I) >> Type >> Id >> PtrId >> MemoryAccess;
- MemoryAccessUpdate(MemoryAccess);
- }
-
- void validate()const {
- SPIRVInstruction::validate();
- assert((getValue(PtrId)->isForward() ||
- Type == getValueType(PtrId)->getPointerElementType()) &&
- "Inconsistent types");
- }
-private:
- SPIRVId PtrId;
- std::vector<SPIRVWord> MemoryAccess;
-};
-
-class SPIRVBinary:public SPIRVInstTemplateBase {
-protected:
- void validate()const {
- SPIRVId Op1 = Ops[0];
- SPIRVId Op2 = Ops[1];
- SPIRVType *op1Ty, *op2Ty;
- SPIRVInstruction::validate();
- if (getValue(Op1)->isForward() || getValue(Op2)->isForward())
- return;
- if (getValueType(Op1)->isTypeVector()) {
- op1Ty = getValueType(Op1)->getVectorComponentType();
- op2Ty = getValueType(Op2)->getVectorComponentType();
- assert(getValueType(Op1)->getVectorComponentCount() ==
- getValueType(Op2)->getVectorComponentCount() &&
- "Inconsistent Vector component width");
- }
- else {
- op1Ty = getValueType(Op1);
- op2Ty = getValueType(Op2);
- }
-
+//===- SPIRVInstruction.h - Class to represent SPIRV instruction -*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines Instruction class for SPIR-V. +/// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVINSTRUCTION_HPP_ +#define SPIRVINSTRUCTION_HPP_ + +#include "SPIRVEnum.h" +#include "SPIRVIsValidEnum.h" +#include "SPIRVStream.h" +#include "SPIRVValue.h" +#include "SPIRVBasicBlock.h" +#include "SPIRVOpCode.h" + +#include <cassert> +#include <cstdint> +#include <functional> +#include <iostream> +#include <map> +#include <utility> +#include <vector> +#include <unordered_set> + +namespace SPIRV{ + +typedef std::vector<SPIRVValue *> ValueVec; +typedef std::pair<ValueVec::iterator, ValueVec::iterator> ValueRange; + +class SPIRVBasicBlock; +class SPIRVFunction; + +bool isSpecConstantOpAllowedOp(Op OC); + +class SPIRVComponentExecutionScope { +public: + SPIRVComponentExecutionScope(Scope TheScope = ScopeInvocation): + ExecScope(TheScope){} + Scope ExecScope; +}; + +class SPIRVComponentMemorySemanticsMask { +public: + SPIRVComponentMemorySemanticsMask(SPIRVWord TheSema = SPIRVWORD_MAX): + MemSema(TheSema){} + SPIRVWord MemSema; +}; + +class SPIRVComponentOperands { +public: + SPIRVComponentOperands(){}; + SPIRVComponentOperands(const std::vector<SPIRVValue *> &TheOperands): + Operands(TheOperands){}; + SPIRVComponentOperands(std::vector<SPIRVValue *> &&TheOperands): + Operands(std::move(TheOperands)){}; + std::vector<SPIRVValue *> getCompOperands() { + return Operands; + } + std::vector<SPIRVType *> getCompOperandTypes() { + std::vector<SPIRVType *> Tys; + for (auto &I:getCompOperands()) + Tys.push_back(I->getType()); + return Tys; + } +protected: + std::vector<SPIRVValue *> Operands; +}; + +class SPIRVInstruction: public SPIRVValue { +public: + // Complete constructor for instruction with type and id + SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, + SPIRVId TheId, SPIRVBasicBlock *TheBB); + // Complete constructor for instruction with module, type and id + SPIRVInstruction(unsigned TheWordCount, Op TheOC, + SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB, + SPIRVModule *TheBM); + // Complete constructor for instruction with id but no type + SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVId TheId, + SPIRVBasicBlock *TheBB); + // Complete constructor for instruction without type and id + SPIRVInstruction(unsigned TheWordCount, Op TheOC, + SPIRVBasicBlock *TheBB); + // Complete constructor for instruction with type but no id + SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, + SPIRVBasicBlock *TheBB); + // Incomplete constructor + SPIRVInstruction(Op TheOC = OpNop):SPIRVValue(TheOC), BB(NULL){} + + virtual bool isInst() const { return true;} + SPIRVBasicBlock *getParent() const {return BB;} + SPIRVInstruction *getPrevious() const { return BB->getPrevious(this);} + SPIRVInstruction *getNext() const { return BB->getNext(this);} + virtual std::vector<SPIRVValue *> getOperands(); + std::vector<SPIRVType*> getOperandTypes(); + static std::vector<SPIRVType*> getOperandTypes( + const std::vector<SPIRVValue *> &Ops); + + void setParent(SPIRVBasicBlock *); + void setScope(SPIRVEntry *); + void addFPRoundingMode(SPIRVFPRoundingModeKind Kind) { + addDecorate(DecorationFPRoundingMode, Kind); + } + void eraseFPRoundingMode() { + eraseDecorate(DecorationFPRoundingMode); + } + void setSaturatedConversion(bool Enable) { + if (Enable) + addDecorate(DecorationSaturatedConversion); + else + eraseDecorate(DecorationSaturatedConversion); + } + bool hasFPRoundingMode(SPIRVFPRoundingModeKind *Kind = nullptr) { + SPIRVWord V; + auto Found = hasDecorate(DecorationFPRoundingMode, 0, &V); + if (Found && Kind) + *Kind = static_cast<SPIRVFPRoundingModeKind>(V); + return Found; + } + bool isSaturatedConversion() { + return hasDecorate(DecorationSaturatedConversion) || + OpCode == OpSatConvertSToU || + OpCode == OpSatConvertUToS; + } + + SPIRVBasicBlock* getBasicBlock() const { + return BB; + } + + void setBasicBlock(SPIRVBasicBlock* TheBB) { + BB = TheBB; + if (TheBB) + setModule(TheBB->getModule()); + } + +protected: + void validate()const { + SPIRVValue::validate(); + } +private: + SPIRVBasicBlock *BB; +}; + +class SPIRVInstTemplateBase:public SPIRVInstruction { +public: + /// Create an empty instruction. Mainly for getting format information, + /// e.g. whether an operand is literal. + static SPIRVInstTemplateBase *create(Op TheOC){ + auto Inst = static_cast<SPIRVInstTemplateBase *>(SPIRVEntry::create(TheOC)); + assert(Inst); + Inst->init(); + return Inst; + } + /// Create a instruction without operands. + static SPIRVInstTemplateBase *create(Op TheOC, SPIRVType *TheType, + SPIRVId TheId, SPIRVBasicBlock *TheBB, + SPIRVModule *TheModule){ + auto Inst = create(TheOC); + Inst->init(TheType, TheId, TheBB, TheModule); + return Inst; + } + /// Create a complete and valid instruction. + static SPIRVInstTemplateBase *create(Op TheOC, SPIRVType *TheType, + SPIRVId TheId, const std::vector<SPIRVWord> &TheOps, SPIRVBasicBlock *TheBB, + SPIRVModule *TheModule){ + auto Inst = create(TheOC); + Inst->init(TheType, TheId, TheBB, TheModule); + Inst->setOpWords(TheOps); + Inst->validate(); + return Inst; + } + SPIRVInstTemplateBase(Op OC = OpNop) + :SPIRVInstruction(OC), HasVariWC(false){ + init(); + } + virtual ~SPIRVInstTemplateBase(){} + SPIRVInstTemplateBase *init(SPIRVType *TheType, + SPIRVId TheId, SPIRVBasicBlock *TheBB, + SPIRVModule *TheModule){ + assert((TheBB || TheModule) && "Invalid BB or Module"); + if (TheBB) + setBasicBlock(TheBB); + else { + setModule(TheModule); + } + setId(hasId() ? TheId : SPIRVID_INVALID); + setType(hasType() ? TheType : nullptr); + return this; + } + virtual void init() {} + virtual void initImpl(Op OC, bool HasId = true, SPIRVWord WC = 0, + bool VariWC = false, unsigned Lit1 = ~0U, + unsigned Lit2 = ~0U, unsigned Lit3 = ~0U){ + OpCode = OC; + if (!HasId) { + setHasNoId(); + setHasNoType(); + } + if (WC) + SPIRVEntry::setWordCount(WC); + setHasVariableWordCount(VariWC); + addLit(Lit1); + addLit(Lit2); + addLit(Lit3); + } + virtual bool isOperandLiteral(unsigned I) const { + return Lit.count(I); + } + void addLit(unsigned L) { + if (L != ~0U) + Lit.insert(L); + } + /// \return Expected number of operands. If the instruction has variable + /// number of words, return the minimum. + SPIRVWord getExpectedNumOperands() const { + assert(WordCount > 0 && "Word count not initialized"); + auto Exp = WordCount - 1; + if (hasId()) + --Exp; + if (hasType()) + --Exp; + return Exp; + } + virtual void setOpWordsAndValidate(const std::vector<SPIRVWord> &TheOps) { + setOpWords(TheOps); + validate(); + } + virtual void setOpWords(const std::vector<SPIRVWord> &TheOps) { + SPIRVWord WC = TheOps.size() + 1; + if (hasId()) + ++WC; + if (hasType()) + ++WC; + if (WordCount) { + if (WordCount == WC) { + // do nothing + } else { + assert(HasVariWC && WC >= WordCount && "Invalid word count"); + SPIRVEntry::setWordCount(WC); + } + } else + SPIRVEntry::setWordCount(WC); + Ops = TheOps; + } + virtual void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + auto NumOps = WordCount - 1; + if (hasId()) + --NumOps; + if (hasType()) + --NumOps; + Ops.resize(NumOps); + } + + std::vector<SPIRVWord> &getOpWords() { + return Ops; + } + + const std::vector<SPIRVWord> &getOpWords() const { + return Ops; + } + + SPIRVWord getOpWord(int I) const { + return Ops[I]; + } + + /// Get operand as value. + /// If the operand is a literal, return it as a uint32 constant. + SPIRVValue *getOpValue(int I) { + return isOperandLiteral(I) ? Module->getLiteralAsConstant(Ops[I]) : + getValue(Ops[I]); + } + + // Get the offset of operands. + // Some instructions skip literals when returning operands. + size_t getOperandOffset() const { + if (hasExecScope() && !isGroupOpCode(OpCode) && !isPipeOpCode(OpCode)) + return 1; + return 0; + } + + // Get operands which are values. + // Drop execution scope and group operation literals. + // Return other literals as uint32 constants. + virtual std::vector<SPIRVValue *> getOperands() { + std::vector<SPIRVValue*> VOps; + auto Offset = getOperandOffset(); + for (size_t I = 0, E = Ops.size() - Offset; I != E; ++I) + VOps.push_back(getOperand(I)); + return VOps; + } + + virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { + std::vector<SPIRVEntry*> Operands; + for (size_t I = getOperandOffset(), E = Ops.size(); I < E; ++I) + if (!isOperandLiteral(I)) + Operands.push_back(getEntry(Ops[I])); + return Operands; + } + + virtual SPIRVValue *getOperand(unsigned I) { + return getOpValue(I + getOperandOffset()); + } + + bool hasExecScope() const { + return SPIRV::hasExecScope(OpCode); + } + + bool hasGroupOperation() const { + return SPIRV::hasGroupOperation(OpCode); + } + + bool getSPIRVGroupOperation(SPIRVGroupOperationKind &GroupOp) const { + if (!hasGroupOperation()) + return false; + GroupOp = static_cast<SPIRVGroupOperationKind>(Ops[1]); + return true; + } + + Scope getExecutionScope() const { + if(!hasExecScope()) + return ScopeInvocation; + return static_cast<Scope>( + static_cast<SPIRVConstant*>(getValue(Ops[0]))->getZExtIntValue()); + } + + bool hasVariableWordCount() const { + return HasVariWC; + } + + void setHasVariableWordCount(bool VariWC) { + HasVariWC = VariWC; + } + +protected: + virtual void encode(spv_ostream &O) const { + auto E = getEncoder(O); + if (hasType()) + E << Type; + if (hasId()) + E << Id; + E << Ops; + } + virtual void decode(std::istream &I) { + auto D = getDecoder(I); + if (hasType()) + D >> Type; + if (hasId()) + D >> Id; + D >> Ops; + } + std::vector<SPIRVWord> Ops; + bool HasVariWC; + std::unordered_set<unsigned> Lit; // Literal operand index +}; + +template<typename BT = SPIRVInstTemplateBase, + Op OC = OpNop, + bool HasId = true, + SPIRVWord WC = 0, + bool HasVariableWC = false, + unsigned Literal1 = ~0U, + unsigned Literal2 = ~0U, + unsigned Literal3 = ~0U> +class SPIRVInstTemplate:public BT { +public: + typedef BT BaseTy; + SPIRVInstTemplate(){ + init(); + } + virtual ~SPIRVInstTemplate(){} + virtual void init() { + this->initImpl(OC, HasId, WC, HasVariableWC, Literal1, Literal2, Literal3); + } +}; + +class SPIRVMemoryAccess { +public: + SPIRVMemoryAccess(const std::vector<SPIRVWord> &TheMemoryAccess): + TheMemoryAccessMask(0), Alignment(0) { + MemoryAccessUpdate(TheMemoryAccess); + } + + SPIRVMemoryAccess() : TheMemoryAccessMask(0), Alignment(0){} + + void MemoryAccessUpdate(const std::vector<SPIRVWord> &MemoryAccess) { + if (!MemoryAccess.size()) + return; + assert((MemoryAccess.size() == 1 || MemoryAccess.size() == 2) && "Invalid memory access operand size"); + TheMemoryAccessMask = MemoryAccess[0]; + if (MemoryAccess[0] & MemoryAccessAlignedMask) { + assert(MemoryAccess.size() == 2 && "Alignment operand is missing"); + Alignment = MemoryAccess[1]; + } + } + SPIRVWord isVolatile() const { return getMemoryAccessMask() & MemoryAccessVolatileMask; } + SPIRVWord isNonTemporal() const { return getMemoryAccessMask() & MemoryAccessNontemporalMask; } + SPIRVWord getMemoryAccessMask() const { return TheMemoryAccessMask; } + SPIRVWord getAlignment() const { return Alignment; } + +protected: + SPIRVWord TheMemoryAccessMask; + SPIRVWord Alignment; +}; + +class SPIRVVariable : public SPIRVInstruction { +public: + // Complete constructor for integer constant + SPIRVVariable(SPIRVType *TheType, SPIRVId TheId, + SPIRVValue *TheInitializer, const std::string &TheName, + SPIRVStorageClassKind TheStorageClass, SPIRVBasicBlock *TheBB, + SPIRVModule *TheM) + :SPIRVInstruction(TheInitializer ? 5 : 4, OpVariable, TheType, + TheId, TheBB, TheM), + StorageClass(TheStorageClass){ + if (TheInitializer) + Initializer.push_back(TheInitializer->getId()); + Name = TheName; + validate(); + } + // Incomplete constructor + SPIRVVariable() :SPIRVInstruction(OpVariable), + StorageClass(StorageClassFunction){} + + SPIRVStorageClassKind getStorageClass() const { return StorageClass; } + SPIRVValue *getInitializer() const { + if (Initializer.empty()) + return nullptr; + assert(Initializer.size() == 1); + return getValue(Initializer[0]); + } + bool isConstant() const { + return hasDecorate(DecorationConstant); + } + bool isBuiltin(SPIRVBuiltinVariableKind *BuiltinKind = nullptr) const { + SPIRVWord Kind; + bool Found = hasDecorate(DecorationBuiltIn, 0, &Kind); + if (!Found) + return false; + if (BuiltinKind) + *BuiltinKind = static_cast<SPIRVBuiltinVariableKind>(Kind); + return true; + } + void setBuiltin(SPIRVBuiltinVariableKind Kind) { + assert(isValid(Kind)); + addDecorate(new SPIRVDecorate(DecorationBuiltIn, this, Kind)); + } + void setIsConstant(bool Is) { + if (Is) + addDecorate(new SPIRVDecorate(DecorationConstant, this)); + else + eraseDecorate(DecorationConstant); + } + virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { + if (SPIRVValue *V = getInitializer()) + return std::vector<SPIRVEntry*>(1, V); + return std::vector<SPIRVEntry*>(); + } +protected: + void validate() const { + SPIRVValue::validate(); + assert(isValid(StorageClass)); + assert(Initializer.size() == 1 || Initializer.empty()); + assert(getType()->isTypePointer()); + } + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + Initializer.resize(WordCount - 4); + } + _SPIRV_DEF_ENCDEC4(Type, Id, StorageClass, Initializer) + + SPIRVStorageClassKind StorageClass; + std::vector<SPIRVId> Initializer; +}; + +class SPIRVStore:public SPIRVInstruction, public SPIRVMemoryAccess { +public: + const static SPIRVWord FixedWords = 3; + // Complete constructor + SPIRVStore(SPIRVId PointerId, SPIRVId ValueId, + const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *TheBB) + :SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OpStore, + TheBB), + SPIRVMemoryAccess(TheMemoryAccess), + MemoryAccess(TheMemoryAccess), + PtrId(PointerId), + ValId(ValueId){ + setAttr(); + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVStore():SPIRVInstruction(OpStore), SPIRVMemoryAccess(), + PtrId(SPIRVID_INVALID), ValId(SPIRVID_INVALID){ + setAttr(); + } + + SPIRVValue *getSrc() const { return getValue(ValId);} + SPIRVValue *getDst() const { return getValue(PtrId);} +protected: + void setAttr() { + setHasNoType(); + setHasNoId(); + } + + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + MemoryAccess.resize(TheWordCount - FixedWords); + } + void encode(spv_ostream &O) const { + getEncoder(O) << PtrId << ValId << MemoryAccess; + } + + void decode(std::istream &I) { + getDecoder(I) >> PtrId >> ValId >> MemoryAccess; + MemoryAccessUpdate(MemoryAccess); + } + + void validate()const { + SPIRVInstruction::validate(); + if (getSrc()->isForward() || getDst()->isForward()) + return; + assert(getValueType(PtrId)->getPointerElementType() == getValueType(ValId) + && "Inconsistent operand types"); + } +private: + std::vector<SPIRVWord> MemoryAccess; + SPIRVId PtrId; + SPIRVId ValId; +}; + +class SPIRVLoad:public SPIRVInstruction, public SPIRVMemoryAccess { +public: + const static SPIRVWord FixedWords = 4; + // Complete constructor + SPIRVLoad(SPIRVId TheId, SPIRVId PointerId, + const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *TheBB) + :SPIRVInstruction(FixedWords + TheMemoryAccess.size() , OpLoad, + TheBB->getValueType(PointerId)->getPointerElementType(), TheId, TheBB), + SPIRVMemoryAccess(TheMemoryAccess), PtrId(PointerId), + MemoryAccess(TheMemoryAccess) { + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVLoad():SPIRVInstruction(OpLoad), SPIRVMemoryAccess(), + PtrId(SPIRVID_INVALID){} + + SPIRVValue *getSrc() const { return Module->get<SPIRVValue>(PtrId);} + +protected: + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + MemoryAccess.resize(TheWordCount - FixedWords); + } + + void encode(spv_ostream &O) const { + getEncoder(O) << Type << Id << PtrId << MemoryAccess; + } + + void decode(std::istream &I) { + getDecoder(I) >> Type >> Id >> PtrId >> MemoryAccess; + MemoryAccessUpdate(MemoryAccess); + } + + void validate()const { + SPIRVInstruction::validate(); + assert((getValue(PtrId)->isForward() || + Type == getValueType(PtrId)->getPointerElementType()) && + "Inconsistent types"); + } +private: + SPIRVId PtrId; + std::vector<SPIRVWord> MemoryAccess; +}; + +class SPIRVBinary:public SPIRVInstTemplateBase { +protected: + void validate()const { + SPIRVId Op1 = Ops[0]; + SPIRVId Op2 = Ops[1]; + SPIRVType *op1Ty, *op2Ty; + SPIRVInstruction::validate(); + if (getValue(Op1)->isForward() || getValue(Op2)->isForward()) + return; + if (getValueType(Op1)->isTypeVector()) { + op1Ty = getValueType(Op1)->getVectorComponentType(); + op2Ty = getValueType(Op2)->getVectorComponentType(); + assert(getValueType(Op1)->getVectorComponentCount() == + getValueType(Op2)->getVectorComponentCount() && + "Inconsistent Vector component width"); + } + else { + op1Ty = getValueType(Op1); + op2Ty = getValueType(Op2); + } + (void)op1Ty; (void)op2Ty; - if (isBinaryOpCode(OpCode)) {
- assert(getValueType(Op1)== getValueType(Op2) &&
- "Invalid type for binary instruction");
- assert((op1Ty->isTypeInt() || op2Ty->isTypeFloat()) &&
- "Invalid type for Binary instruction");
- assert((op1Ty->getBitWidth() == op2Ty->getBitWidth()) &&
- "Inconsistent BitWidth");
- } else if (isShiftOpCode(OpCode)) {
- assert((op1Ty->isTypeInt() || op2Ty->isTypeInt()) &&
- "Invalid type for shift instruction");
- } else if (isLogicalOpCode(OpCode)) {
- assert((op1Ty->isTypeBool() || op2Ty->isTypeBool()) &&
- "Invalid type for logical instruction");
- } else if (isBitwiseOpCode(OpCode)) {
- assert((op1Ty->isTypeInt() || op2Ty->isTypeInt()) &&
- "Invalid type for bitwise instruction");
- assert((op1Ty->getIntegerBitWidth() == op2Ty->getIntegerBitWidth()) &&
- "Inconsistent BitWidth");
- } else {
- assert(0 && "Invalid op code!");
- }
- }
-};
-
-template<Op OC>
-class SPIRVBinaryInst:public SPIRVInstTemplate<SPIRVBinary, OC, true, 5, false> {
-};
-
-/* ToDo: SMod and FMod to be added */
-#define _SPIRV_OP(x) typedef SPIRVBinaryInst<Op##x> SPIRV##x;
-_SPIRV_OP(IAdd)
-_SPIRV_OP(FAdd)
-_SPIRV_OP(ISub)
-_SPIRV_OP(FSub)
-_SPIRV_OP(IMul)
-_SPIRV_OP(FMul)
-_SPIRV_OP(UDiv)
-_SPIRV_OP(SDiv)
-_SPIRV_OP(FDiv)
-_SPIRV_OP(SRem)
-_SPIRV_OP(FRem)
-_SPIRV_OP(UMod)
-_SPIRV_OP(ShiftLeftLogical)
-_SPIRV_OP(ShiftRightLogical)
-_SPIRV_OP(ShiftRightArithmetic)
-_SPIRV_OP(LogicalAnd)
-_SPIRV_OP(LogicalOr)
-_SPIRV_OP(LogicalEqual)
-_SPIRV_OP(LogicalNotEqual)
-_SPIRV_OP(BitwiseAnd)
-_SPIRV_OP(BitwiseOr)
-_SPIRV_OP(BitwiseXor)
-_SPIRV_OP(Dot)
-#undef _SPIRV_OP
-
-template<Op TheOpCode>
-class SPIRVInstNoOperand:public SPIRVInstruction {
-public:
- // Complete constructor
- SPIRVInstNoOperand(SPIRVBasicBlock *TheBB):SPIRVInstruction(1, TheOpCode,
- TheBB){
- setAttr();
- validate();
- }
- // Incomplete constructor
- SPIRVInstNoOperand():SPIRVInstruction(TheOpCode){
- setAttr();
- }
-protected:
- void setAttr() {
- setHasNoId();
- setHasNoType();
- }
- _SPIRV_DEF_ENCDEC0
-};
-
-typedef SPIRVInstNoOperand<OpReturn> SPIRVReturn;
-typedef SPIRVInstNoOperand<OpUnreachable> SPIRVUnreachable;
-
-class SPIRVReturnValue:public SPIRVInstruction {
-public:
- static const Op OC = OpReturnValue;
- // Complete constructor
- SPIRVReturnValue(SPIRVValue *TheReturnValue, SPIRVBasicBlock *TheBB)
- :SPIRVInstruction(2, OC, TheBB), ReturnValueId(TheReturnValue->getId()){
- setAttr();
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVReturnValue():SPIRVInstruction(OC), ReturnValueId(SPIRVID_INVALID) {
- setAttr();
- }
-
- SPIRVValue *getReturnValue() const {
- return getValue(ReturnValueId);
- }
-protected:
- void setAttr() {
- setHasNoId();
- setHasNoType();
- }
- _SPIRV_DEF_ENCDEC1(ReturnValueId)
- void validate()const {
- SPIRVInstruction::validate();
- }
- SPIRVId ReturnValueId;
-};
-
-class SPIRVBranch:public SPIRVInstruction {
-public:
- static const Op OC = OpBranch;
- // Complete constructor
- SPIRVBranch(SPIRVLabel *TheTargetLabel,SPIRVBasicBlock *TheBB)
- :SPIRVInstruction(2, OC, TheBB), TargetLabelId(TheTargetLabel->getId()) {
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVBranch():SPIRVInstruction(OC), TargetLabelId(SPIRVID_INVALID) {
- setHasNoId();
- setHasNoType();
- }
- SPIRVValue *getTargetLabel() const {
- return getValue(TargetLabelId);
- }
-protected:
- _SPIRV_DEF_ENCDEC1(TargetLabelId)
- void validate()const {
- SPIRVInstruction::validate();
- assert(WordCount == 2);
- assert(OpCode == OC);
- assert(getTargetLabel()->isLabel() || getTargetLabel()->isForward());
- }
- SPIRVId TargetLabelId;
-};
-
-class SPIRVBranchConditional:public SPIRVInstruction {
-public:
- static const Op OC = OpBranchConditional;
- // Complete constructor
- SPIRVBranchConditional(SPIRVValue *TheCondition, SPIRVLabel *TheTrueLabel,
- SPIRVLabel *TheFalseLabel, SPIRVBasicBlock *TheBB)
- :SPIRVInstruction(4, OC, TheBB), ConditionId(TheCondition->getId()),
- TrueLabelId(TheTrueLabel->getId()), FalseLabelId(TheFalseLabel->getId()){
- validate();
- }
- SPIRVBranchConditional(SPIRVValue *TheCondition, SPIRVLabel *TheTrueLabel,
- SPIRVLabel *TheFalseLabel, SPIRVBasicBlock *TheBB, SPIRVWord TrueWeight,
- SPIRVWord FalseWeight)
- :SPIRVInstruction(6, OC, TheBB), ConditionId(TheCondition->getId()),
- TrueLabelId(TheTrueLabel->getId()), FalseLabelId(TheFalseLabel->getId()){
- BranchWeights.push_back(TrueWeight);
- BranchWeights.push_back(FalseWeight);
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVBranchConditional():SPIRVInstruction(OC), ConditionId(SPIRVID_INVALID),
- TrueLabelId(SPIRVID_INVALID), FalseLabelId(SPIRVID_INVALID) {
- setHasNoId();
- setHasNoType();
- }
- SPIRVValue *getCondition() const {
- return getValue(ConditionId);
- }
- SPIRVLabel *getTrueLabel() const {
- return get<SPIRVLabel>(TrueLabelId);
- }
- SPIRVLabel *getFalseLabel() const {
- return get<SPIRVLabel>(FalseLabelId);
- }
-protected:
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- BranchWeights.resize(TheWordCount - 4);
- }
- _SPIRV_DEF_ENCDEC4(ConditionId, TrueLabelId, FalseLabelId, BranchWeights)
- void validate()const {
- SPIRVInstruction::validate();
- assert(WordCount == 4 || WordCount == 6);
- assert(WordCount == BranchWeights.size() + 4);
- assert(OpCode == OC);
- assert(getCondition()->isForward() ||
- getCondition()->getType()->isTypeBool());
- assert(getTrueLabel()->isForward() || getTrueLabel()->isLabel());
- assert(getFalseLabel()->isForward() || getFalseLabel()->isLabel());
- }
- SPIRVId ConditionId;
- SPIRVId TrueLabelId;
- SPIRVId FalseLabelId;
- std::vector<SPIRVWord> BranchWeights;
-};
-
-class SPIRVPhi: public SPIRVInstruction {
-public:
- static const Op OC = OpPhi;
- static const SPIRVWord FixedWordCount = 3;
- SPIRVPhi(SPIRVType *TheType, SPIRVId TheId,
- const std::vector<SPIRVValue *> &ThePairs, SPIRVBasicBlock *BB)
- :SPIRVInstruction(ThePairs.size() + FixedWordCount, OC, TheType, TheId, BB){
- Pairs = getIds(ThePairs);
- validate();
- assert(BB && "Invalid BB");
- }
- SPIRVPhi():SPIRVInstruction(OC) {}
- std::vector<SPIRVValue *> getPairs() {
- return getValues(Pairs);
- }
- void addPair(SPIRVValue *Value, SPIRVBasicBlock *BB) {
- Pairs.push_back(Value->getId());
- Pairs.push_back(BB->getId());
- WordCount = Pairs.size() + FixedWordCount;
- validate();
- }
- void setPairs(const std::vector<SPIRVValue *> &ThePairs) {
- Pairs = getIds(ThePairs);
- WordCount = Pairs.size() + FixedWordCount;
- validate();
- }
- void foreachPair(std::function<void(SPIRVValue *, SPIRVBasicBlock *,
- size_t)> Func) {
- for (size_t I = 0, E = Pairs.size()/2; I != E; ++I) {
- SPIRVEntry *Value, *BB;
- if (!Module->exist(Pairs[2*I], &Value) ||
- !Module->exist(Pairs[2*I+1], &BB))
- continue;
- Func(static_cast<SPIRVValue *>(Value), static_cast<SPIRVBasicBlock *>(BB),
- I);
- }
- }
- void foreachPair(std::function<void(SPIRVValue *, SPIRVBasicBlock *)> Func)
- const {
- for (size_t I = 0, E = Pairs.size()/2; I != E; ++I) {
- SPIRVEntry *Value, *BB;
- if (!Module->exist(Pairs[2*I], &Value) ||
- !Module->exist(Pairs[2*I+1], &BB))
- continue;
- Func(static_cast<SPIRVValue *>(Value), static_cast<SPIRVBasicBlock *>(BB));
- }
- }
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- Pairs.resize(TheWordCount - FixedWordCount);
- }
- _SPIRV_DEF_ENCDEC3(Type, Id, Pairs)
- void validate()const {
- assert(WordCount == Pairs.size() + FixedWordCount);
- assert(OpCode == OC);
- assert(Pairs.size() % 2 == 0);
- foreachPair([=](SPIRVValue *IncomingV, SPIRVBasicBlock *IncomingBB){
- assert(IncomingV->isForward() || IncomingV->getType() == Type);
- assert(IncomingBB->isBasicBlock() || IncomingBB->isForward());
- });
- SPIRVInstruction::validate();
- }
-protected:
- std::vector<SPIRVId> Pairs;
-};
-
-class SPIRVCompare:public SPIRVInstTemplateBase {
-protected:
- void validate()const {
- auto Op1 = Ops[0];
- auto Op2 = Ops[1];
- SPIRVType *op1Ty, *op2Ty, *resTy;
- SPIRVInstruction::validate();
- if (getValue(Op1)->isForward() || getValue(Op2)->isForward())
- return;
-
+ if (isBinaryOpCode(OpCode)) { + assert(getValueType(Op1)== getValueType(Op2) && + "Invalid type for binary instruction"); + assert((op1Ty->isTypeInt() || op2Ty->isTypeFloat()) && + "Invalid type for Binary instruction"); + assert((op1Ty->getBitWidth() == op2Ty->getBitWidth()) && + "Inconsistent BitWidth"); + } else if (isShiftOpCode(OpCode)) { + assert((op1Ty->isTypeInt() || op2Ty->isTypeInt()) && + "Invalid type for shift instruction"); + } else if (isLogicalOpCode(OpCode)) { + assert((op1Ty->isTypeBool() || op2Ty->isTypeBool()) && + "Invalid type for logical instruction"); + } else if (isBitwiseOpCode(OpCode)) { + assert((op1Ty->isTypeInt() || op2Ty->isTypeInt()) && + "Invalid type for bitwise instruction"); + assert((op1Ty->getIntegerBitWidth() == op2Ty->getIntegerBitWidth()) && + "Inconsistent BitWidth"); + } else { + assert(0 && "Invalid op code!"); + } + } +}; + +template<Op OC> +class SPIRVBinaryInst:public SPIRVInstTemplate<SPIRVBinary, OC, true, 5, false> { +}; + +/* ToDo: SMod and FMod to be added */ +#define _SPIRV_OP(x) typedef SPIRVBinaryInst<Op##x> SPIRV##x; +_SPIRV_OP(IAdd) +_SPIRV_OP(FAdd) +_SPIRV_OP(ISub) +_SPIRV_OP(FSub) +_SPIRV_OP(IMul) +_SPIRV_OP(FMul) +_SPIRV_OP(UDiv) +_SPIRV_OP(SDiv) +_SPIRV_OP(FDiv) +_SPIRV_OP(SRem) +_SPIRV_OP(FRem) +_SPIRV_OP(UMod) +_SPIRV_OP(ShiftLeftLogical) +_SPIRV_OP(ShiftRightLogical) +_SPIRV_OP(ShiftRightArithmetic) +_SPIRV_OP(LogicalAnd) +_SPIRV_OP(LogicalOr) +_SPIRV_OP(LogicalEqual) +_SPIRV_OP(LogicalNotEqual) +_SPIRV_OP(BitwiseAnd) +_SPIRV_OP(BitwiseOr) +_SPIRV_OP(BitwiseXor) +_SPIRV_OP(Dot) +#undef _SPIRV_OP + +template<Op TheOpCode> +class SPIRVInstNoOperand:public SPIRVInstruction { +public: + // Complete constructor + SPIRVInstNoOperand(SPIRVBasicBlock *TheBB):SPIRVInstruction(1, TheOpCode, + TheBB){ + setAttr(); + validate(); + } + // Incomplete constructor + SPIRVInstNoOperand():SPIRVInstruction(TheOpCode){ + setAttr(); + } +protected: + void setAttr() { + setHasNoId(); + setHasNoType(); + } + _SPIRV_DEF_ENCDEC0 +}; + +typedef SPIRVInstNoOperand<OpReturn> SPIRVReturn; +typedef SPIRVInstNoOperand<OpUnreachable> SPIRVUnreachable; + +class SPIRVReturnValue:public SPIRVInstruction { +public: + static const Op OC = OpReturnValue; + // Complete constructor + SPIRVReturnValue(SPIRVValue *TheReturnValue, SPIRVBasicBlock *TheBB) + :SPIRVInstruction(2, OC, TheBB), ReturnValueId(TheReturnValue->getId()){ + setAttr(); + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVReturnValue():SPIRVInstruction(OC), ReturnValueId(SPIRVID_INVALID) { + setAttr(); + } + + SPIRVValue *getReturnValue() const { + return getValue(ReturnValueId); + } +protected: + void setAttr() { + setHasNoId(); + setHasNoType(); + } + _SPIRV_DEF_ENCDEC1(ReturnValueId) + void validate()const { + SPIRVInstruction::validate(); + } + SPIRVId ReturnValueId; +}; + +class SPIRVBranch:public SPIRVInstruction { +public: + static const Op OC = OpBranch; + // Complete constructor + SPIRVBranch(SPIRVLabel *TheTargetLabel,SPIRVBasicBlock *TheBB) + :SPIRVInstruction(2, OC, TheBB), TargetLabelId(TheTargetLabel->getId()) { + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVBranch():SPIRVInstruction(OC), TargetLabelId(SPIRVID_INVALID) { + setHasNoId(); + setHasNoType(); + } + SPIRVValue *getTargetLabel() const { + return getValue(TargetLabelId); + } +protected: + _SPIRV_DEF_ENCDEC1(TargetLabelId) + void validate()const { + SPIRVInstruction::validate(); + assert(WordCount == 2); + assert(OpCode == OC); + assert(getTargetLabel()->isLabel() || getTargetLabel()->isForward()); + } + SPIRVId TargetLabelId; +}; + +class SPIRVBranchConditional:public SPIRVInstruction { +public: + static const Op OC = OpBranchConditional; + // Complete constructor + SPIRVBranchConditional(SPIRVValue *TheCondition, SPIRVLabel *TheTrueLabel, + SPIRVLabel *TheFalseLabel, SPIRVBasicBlock *TheBB) + :SPIRVInstruction(4, OC, TheBB), ConditionId(TheCondition->getId()), + TrueLabelId(TheTrueLabel->getId()), FalseLabelId(TheFalseLabel->getId()){ + validate(); + } + SPIRVBranchConditional(SPIRVValue *TheCondition, SPIRVLabel *TheTrueLabel, + SPIRVLabel *TheFalseLabel, SPIRVBasicBlock *TheBB, SPIRVWord TrueWeight, + SPIRVWord FalseWeight) + :SPIRVInstruction(6, OC, TheBB), ConditionId(TheCondition->getId()), + TrueLabelId(TheTrueLabel->getId()), FalseLabelId(TheFalseLabel->getId()){ + BranchWeights.push_back(TrueWeight); + BranchWeights.push_back(FalseWeight); + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVBranchConditional():SPIRVInstruction(OC), ConditionId(SPIRVID_INVALID), + TrueLabelId(SPIRVID_INVALID), FalseLabelId(SPIRVID_INVALID) { + setHasNoId(); + setHasNoType(); + } + SPIRVValue *getCondition() const { + return getValue(ConditionId); + } + SPIRVLabel *getTrueLabel() const { + return get<SPIRVLabel>(TrueLabelId); + } + SPIRVLabel *getFalseLabel() const { + return get<SPIRVLabel>(FalseLabelId); + } +protected: + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + BranchWeights.resize(TheWordCount - 4); + } + _SPIRV_DEF_ENCDEC4(ConditionId, TrueLabelId, FalseLabelId, BranchWeights) + void validate()const { + SPIRVInstruction::validate(); + assert(WordCount == 4 || WordCount == 6); + assert(WordCount == BranchWeights.size() + 4); + assert(OpCode == OC); + assert(getCondition()->isForward() || + getCondition()->getType()->isTypeBool()); + assert(getTrueLabel()->isForward() || getTrueLabel()->isLabel()); + assert(getFalseLabel()->isForward() || getFalseLabel()->isLabel()); + } + SPIRVId ConditionId; + SPIRVId TrueLabelId; + SPIRVId FalseLabelId; + std::vector<SPIRVWord> BranchWeights; +}; + +class SPIRVPhi: public SPIRVInstruction { +public: + static const Op OC = OpPhi; + static const SPIRVWord FixedWordCount = 3; + SPIRVPhi(SPIRVType *TheType, SPIRVId TheId, + const std::vector<SPIRVValue *> &ThePairs, SPIRVBasicBlock *BB) + :SPIRVInstruction(ThePairs.size() + FixedWordCount, OC, TheType, TheId, BB){ + Pairs = getIds(ThePairs); + validate(); + assert(BB && "Invalid BB"); + } + SPIRVPhi():SPIRVInstruction(OC) {} + std::vector<SPIRVValue *> getPairs() { + return getValues(Pairs); + } + void addPair(SPIRVValue *Value, SPIRVBasicBlock *BB) { + Pairs.push_back(Value->getId()); + Pairs.push_back(BB->getId()); + WordCount = Pairs.size() + FixedWordCount; + validate(); + } + void setPairs(const std::vector<SPIRVValue *> &ThePairs) { + Pairs = getIds(ThePairs); + WordCount = Pairs.size() + FixedWordCount; + validate(); + } + void foreachPair(std::function<void(SPIRVValue *, SPIRVBasicBlock *, + size_t)> Func) { + for (size_t I = 0, E = Pairs.size()/2; I != E; ++I) { + SPIRVEntry *Value, *BB; + if (!Module->exist(Pairs[2*I], &Value) || + !Module->exist(Pairs[2*I+1], &BB)) + continue; + Func(static_cast<SPIRVValue *>(Value), static_cast<SPIRVBasicBlock *>(BB), + I); + } + } + void foreachPair(std::function<void(SPIRVValue *, SPIRVBasicBlock *)> Func) + const { + for (size_t I = 0, E = Pairs.size()/2; I != E; ++I) { + SPIRVEntry *Value, *BB; + if (!Module->exist(Pairs[2*I], &Value) || + !Module->exist(Pairs[2*I+1], &BB)) + continue; + Func(static_cast<SPIRVValue *>(Value), static_cast<SPIRVBasicBlock *>(BB)); + } + } + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + Pairs.resize(TheWordCount - FixedWordCount); + } + _SPIRV_DEF_ENCDEC3(Type, Id, Pairs) + void validate()const { + assert(WordCount == Pairs.size() + FixedWordCount); + assert(OpCode == OC); + assert(Pairs.size() % 2 == 0); + foreachPair([=](SPIRVValue *IncomingV, SPIRVBasicBlock *IncomingBB){ + assert(IncomingV->isForward() || IncomingV->getType() == Type); + assert(IncomingBB->isBasicBlock() || IncomingBB->isForward()); + }); + SPIRVInstruction::validate(); + } +protected: + std::vector<SPIRVId> Pairs; +}; + +class SPIRVCompare:public SPIRVInstTemplateBase { +protected: + void validate()const { + auto Op1 = Ops[0]; + auto Op2 = Ops[1]; + SPIRVType *op1Ty, *op2Ty, *resTy; + SPIRVInstruction::validate(); + if (getValue(Op1)->isForward() || getValue(Op2)->isForward()) + return; + (void)op1Ty; (void)op2Ty; (void)resTy; - if (getValueType(Op1)->isTypeVector()) {
- op1Ty = getValueType(Op1)->getVectorComponentType();
- op2Ty = getValueType(Op2)->getVectorComponentType();
- resTy = Type->getVectorComponentType();
- assert(getValueType(Op1)->getVectorComponentCount() ==
- getValueType(Op2)->getVectorComponentCount() &&
- "Inconsistent Vector component width");
- }
- else {
- op1Ty = getValueType(Op1);
- op2Ty = getValueType(Op2);
- resTy = Type;
- }
- assert(isCmpOpCode(OpCode) && "Invalid op code for cmp inst");
- assert((resTy->isTypeBool() || resTy->isTypeInt()) &&
- "Invalid type for compare instruction");
- assert(op1Ty == op2Ty && "Inconsistent types");
- }
-};
-
-template<Op OC>
-class SPIRVCmpInst:public SPIRVInstTemplate<SPIRVCompare, OC, true, 5, false> {
-};
-
-#define _SPIRV_OP(x) typedef SPIRVCmpInst<Op##x> SPIRV##x;
-_SPIRV_OP(IEqual)
-_SPIRV_OP(FOrdEqual)
-_SPIRV_OP(FUnordEqual)
-_SPIRV_OP(INotEqual)
-_SPIRV_OP(FOrdNotEqual)
-_SPIRV_OP(FUnordNotEqual)
-_SPIRV_OP(ULessThan)
-_SPIRV_OP(SLessThan)
-_SPIRV_OP(FOrdLessThan)
-_SPIRV_OP(FUnordLessThan)
-_SPIRV_OP(UGreaterThan)
-_SPIRV_OP(SGreaterThan)
-_SPIRV_OP(FOrdGreaterThan)
-_SPIRV_OP(FUnordGreaterThan)
-_SPIRV_OP(ULessThanEqual)
-_SPIRV_OP(SLessThanEqual)
-_SPIRV_OP(FOrdLessThanEqual)
-_SPIRV_OP(FUnordLessThanEqual)
-_SPIRV_OP(UGreaterThanEqual)
-_SPIRV_OP(SGreaterThanEqual)
-_SPIRV_OP(FOrdGreaterThanEqual)
-_SPIRV_OP(FUnordGreaterThanEqual)
-_SPIRV_OP(LessOrGreater)
-_SPIRV_OP(Ordered)
-_SPIRV_OP(Unordered)
-#undef _SPIRV_OP
-
-class SPIRVSelect:public SPIRVInstruction {
-public:
- // Complete constructor
- SPIRVSelect(SPIRVId TheId, SPIRVId TheCondition, SPIRVId TheOp1, SPIRVId TheOp2,
- SPIRVBasicBlock *TheBB)
- :SPIRVInstruction(6, OpSelect, TheBB->getValueType(TheOp1), TheId,
- TheBB), Condition(TheCondition), Op1(TheOp1), Op2(TheOp2){
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVSelect():SPIRVInstruction(OpSelect), Condition(SPIRVID_INVALID),
- Op1(SPIRVID_INVALID), Op2(SPIRVID_INVALID){}
- SPIRVValue *getCondition() { return getValue(Condition);}
- SPIRVValue *getTrueValue() { return getValue(Op1);}
- SPIRVValue *getFalseValue() { return getValue(Op2);}
-protected:
- _SPIRV_DEF_ENCDEC5(Type, Id, Condition, Op1, Op2)
- void validate()const {
- SPIRVInstruction::validate();
- if (getValue(Condition)->isForward() ||
- getValue(Op1)->isForward() ||
- getValue(Op2)->isForward())
- return;
-
- SPIRVType *conTy = getValueType(Condition)->isTypeVector() ?
- getValueType(Condition)->getVectorComponentType() :
- getValueType(Condition);
+ if (getValueType(Op1)->isTypeVector()) { + op1Ty = getValueType(Op1)->getVectorComponentType(); + op2Ty = getValueType(Op2)->getVectorComponentType(); + resTy = Type->getVectorComponentType(); + assert(getValueType(Op1)->getVectorComponentCount() == + getValueType(Op2)->getVectorComponentCount() && + "Inconsistent Vector component width"); + } + else { + op1Ty = getValueType(Op1); + op2Ty = getValueType(Op2); + resTy = Type; + } + assert(isCmpOpCode(OpCode) && "Invalid op code for cmp inst"); + assert((resTy->isTypeBool() || resTy->isTypeInt()) && + "Invalid type for compare instruction"); + assert(op1Ty == op2Ty && "Inconsistent types"); + } +}; + +template<Op OC> +class SPIRVCmpInst:public SPIRVInstTemplate<SPIRVCompare, OC, true, 5, false> { +}; + +#define _SPIRV_OP(x) typedef SPIRVCmpInst<Op##x> SPIRV##x; +_SPIRV_OP(IEqual) +_SPIRV_OP(FOrdEqual) +_SPIRV_OP(FUnordEqual) +_SPIRV_OP(INotEqual) +_SPIRV_OP(FOrdNotEqual) +_SPIRV_OP(FUnordNotEqual) +_SPIRV_OP(ULessThan) +_SPIRV_OP(SLessThan) +_SPIRV_OP(FOrdLessThan) +_SPIRV_OP(FUnordLessThan) +_SPIRV_OP(UGreaterThan) +_SPIRV_OP(SGreaterThan) +_SPIRV_OP(FOrdGreaterThan) +_SPIRV_OP(FUnordGreaterThan) +_SPIRV_OP(ULessThanEqual) +_SPIRV_OP(SLessThanEqual) +_SPIRV_OP(FOrdLessThanEqual) +_SPIRV_OP(FUnordLessThanEqual) +_SPIRV_OP(UGreaterThanEqual) +_SPIRV_OP(SGreaterThanEqual) +_SPIRV_OP(FOrdGreaterThanEqual) +_SPIRV_OP(FUnordGreaterThanEqual) +_SPIRV_OP(LessOrGreater) +_SPIRV_OP(Ordered) +_SPIRV_OP(Unordered) +#undef _SPIRV_OP + +class SPIRVSelect:public SPIRVInstruction { +public: + // Complete constructor + SPIRVSelect(SPIRVId TheId, SPIRVId TheCondition, SPIRVId TheOp1, SPIRVId TheOp2, + SPIRVBasicBlock *TheBB) + :SPIRVInstruction(6, OpSelect, TheBB->getValueType(TheOp1), TheId, + TheBB), Condition(TheCondition), Op1(TheOp1), Op2(TheOp2){ + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVSelect():SPIRVInstruction(OpSelect), Condition(SPIRVID_INVALID), + Op1(SPIRVID_INVALID), Op2(SPIRVID_INVALID){} + SPIRVValue *getCondition() { return getValue(Condition);} + SPIRVValue *getTrueValue() { return getValue(Op1);} + SPIRVValue *getFalseValue() { return getValue(Op2);} +protected: + _SPIRV_DEF_ENCDEC5(Type, Id, Condition, Op1, Op2) + void validate()const { + SPIRVInstruction::validate(); + if (getValue(Condition)->isForward() || + getValue(Op1)->isForward() || + getValue(Op2)->isForward()) + return; + + SPIRVType *conTy = getValueType(Condition)->isTypeVector() ? + getValueType(Condition)->getVectorComponentType() : + getValueType(Condition); (void)conTy; - assert(conTy->isTypeBool() && "Invalid type");
- assert(getType() == getValueType(Op1) && getType() == getValueType(Op2) &&
- "Inconsistent type");
- }
- SPIRVId Condition;
- SPIRVId Op1;
- SPIRVId Op2;
-};
-
-class SPIRVSelectionMerge: public SPIRVInstruction {
-public:
- static const Op OC = OpSelectionMerge;
- static const SPIRVWord FixedWordCount = 3;
-
- SPIRVSelectionMerge(SPIRVId TheMergeBlock,
- SPIRVWord TheSelectionControl, SPIRVBasicBlock *BB)
- :SPIRVInstruction(3, OC, BB), MergeBlock(TheMergeBlock),
- SelectionControl(TheSelectionControl) {
- validate();
- assert(BB && "Invalid BB");
- }
-
- SPIRVSelectionMerge() :SPIRVInstruction(OC), MergeBlock(SPIRVID_INVALID),
- SelectionControl(SPIRVWORD_MAX) {
- setHasNoId();
- setHasNoType();
- }
-
- SPIRVId getMergeBlock() { return MergeBlock; }
- SPIRVWord getSelectionControl() { return SelectionControl; }
-
- _SPIRV_DEF_ENCDEC2(MergeBlock, SelectionControl)
-
-protected:
- SPIRVId MergeBlock;
- SPIRVWord SelectionControl;
-};
-
-class SPIRVLoopMerge : public SPIRVInstruction {
-public:
- static const Op OC = OpLoopMerge;
- static const SPIRVWord FixedWordCount = 4;
-
- SPIRVLoopMerge(SPIRVId TheMergeBlock, SPIRVId TheContinueTarget,
- SPIRVWord TheLoopControl, SPIRVBasicBlock *BB)
- :SPIRVInstruction(FixedWordCount, OC, BB), MergeBlock(TheMergeBlock),
- ContinueTarget(TheContinueTarget), LoopControl(TheLoopControl) {
- validate();
- assert(BB && "Invalid BB");
- }
-
- SPIRVLoopMerge() : SPIRVInstruction(OC), MergeBlock(SPIRVID_MAX),
- LoopControl(SPIRVWORD_MAX) {
- setHasNoId();
- setHasNoType();
- }
-
- SPIRVId getMergeBlock() { return MergeBlock; }
- SPIRVId getContinueTarget() { return ContinueTarget; }
- SPIRVWord getLoopControl() { return LoopControl; }
- _SPIRV_DEF_ENCDEC3(MergeBlock, ContinueTarget, LoopControl)
-
-protected:
- SPIRVId MergeBlock;
- SPIRVId ContinueTarget;
- SPIRVWord LoopControl;
-};
-
-class SPIRVSwitch: public SPIRVInstruction {
-public:
- static const Op OC = OpSwitch;
- static const SPIRVWord FixedWordCount = 3;
- typedef std::vector<SPIRVWord> LiteralTy;
- typedef std::pair<LiteralTy, SPIRVBasicBlock *> PairTy;
-
- SPIRVSwitch(SPIRVValue *TheSelect, SPIRVBasicBlock *TheDefault,
- const std::vector<PairTy> &ThePairs,
- SPIRVBasicBlock *BB)
- :SPIRVInstruction(ThePairs.size() * (ThePairs.at(0).first.size() + 1) + FixedWordCount, OC, BB),
- Select(TheSelect->getId()), Default(TheDefault->getId()) {
-
- for (auto &I : ThePairs) {
- for (auto &U : I.first)
- Pairs.push_back(U);
- Pairs.push_back(I.second->getId());
- }
- validate();
- assert(BB && "Invalid BB");
- }
- SPIRVSwitch():SPIRVInstruction(OC), Select(SPIRVWORD_MAX),
- Default(SPIRVWORD_MAX) {
- setHasNoId();
- setHasNoType();
- }
- std::vector<SPIRVValue *> getPairs() {
- return getValues(Pairs);
- }
- SPIRVValue *getSelect() const { return getValue(Select);}
- SPIRVBasicBlock *getDefault() const {
- return static_cast<SPIRVBasicBlock *>(getValue(Default));
- }
- size_t getLiteralsCount() const { return getSelect()->getType()->getBitWidth() / (sizeof(SPIRVWord) * 8);}
- size_t getPairSize() const { return getLiteralsCount() + 1; }
- size_t getNumPairs() const { return Pairs.size()/getPairSize();}
- void foreachPair(std::function<void(LiteralTy, SPIRVBasicBlock *)> Func)
- const {
- unsigned PairSize = getPairSize();
- for (size_t I = 0, E = getNumPairs(); I != E; ++I) {
- SPIRVEntry *BB;
- LiteralTy Literals;
- if (!Module->exist(Pairs[PairSize*I + getLiteralsCount()], &BB))
- continue;
-
- for (size_t i = 0; i < getLiteralsCount(); ++i) {
- Literals.push_back(Pairs.at(PairSize*I + i));
- }
- Func(Literals, static_cast<SPIRVBasicBlock *>(BB));
- }
- }
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- Pairs.resize(TheWordCount - FixedWordCount);
- }
- _SPIRV_DEF_ENCDEC3(Select, Default, Pairs)
- void validate()const {
- assert(WordCount == Pairs.size() + FixedWordCount);
- assert(OpCode == OC);
- assert(Pairs.size() % getPairSize() == 0);
- foreachPair([=](LiteralTy Literals, SPIRVBasicBlock *BB){
- assert(BB->isBasicBlock() || BB->isForward());
- });
- SPIRVInstruction::validate();
- }
-protected:
- SPIRVId Select;
- SPIRVId Default;
- std::vector<SPIRVWord> Pairs;
-};
-
-class SPIRVFMod : public SPIRVInstruction {
-public:
- static const Op OC = OpFMod;
- static const SPIRVWord FixedWordCount = 4;
- // Complete constructor
- SPIRVFMod(SPIRVType *TheType, SPIRVId TheId, SPIRVId TheDividend,
- SPIRVId TheDivisor, SPIRVBasicBlock *BB)
- :SPIRVInstruction(5, OC, TheType, TheId, BB), Dividend(TheDividend), Divisor(TheDivisor) {
- validate();
- assert(BB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVFMod() :SPIRVInstruction(OC), Dividend(SPIRVID_INVALID),
- Divisor(SPIRVID_INVALID) {
- }
- SPIRVValue *getDividend() const { return getValue(Dividend); }
- SPIRVValue *getDivisor() const { return getValue(Divisor); }
-
- std::vector<SPIRVValue*> getOperands() {
- std::vector<SPIRVId> Operands;
- Operands.push_back(Dividend);
- Operands.push_back(Divisor);
- return getValues(Operands);
- }
-
- void setWordCount(SPIRVWord FixedWordCount) {
- SPIRVEntry::setWordCount(FixedWordCount);
- }
- _SPIRV_DEF_ENCDEC4(Type, Id, Dividend, Divisor)
- void validate()const {
- SPIRVInstruction::validate();
- if (getValue(Dividend)->isForward() ||
- getValue(Divisor)->isForward())
- return;
- SPIRVInstruction::validate();
- }
-protected:
- SPIRVId Dividend;
- SPIRVId Divisor;
-};
-
-class SPIRVVectorTimesScalar : public SPIRVInstruction {
-public:
- static const Op OC = OpVectorTimesScalar;
- static const SPIRVWord FixedWordCount = 4;
- // Complete constructor
- SPIRVVectorTimesScalar(SPIRVType *TheType, SPIRVId TheId, SPIRVId TheVector,
- SPIRVId TheScalar, SPIRVBasicBlock *BB)
- :SPIRVInstruction(5, OC, TheType, TheId, BB), Vector(TheVector), Scalar(TheScalar) {
- validate();
- assert(BB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVVectorTimesScalar() :SPIRVInstruction(OC), Vector(SPIRVID_INVALID),
- Scalar(SPIRVID_INVALID) {
- }
- SPIRVValue *getVector() const { return getValue(Vector); }
- SPIRVValue *getScalar() const { return getValue(Scalar); }
-
- std::vector<SPIRVValue*> getOperands() {
- std::vector<SPIRVId> Operands;
- Operands.push_back(Vector);
- Operands.push_back(Scalar);
- return getValues(Operands);
- }
-
- void setWordCount(SPIRVWord FixedWordCount) {
- SPIRVEntry::setWordCount(FixedWordCount);
- }
- _SPIRV_DEF_ENCDEC4(Type, Id, Vector, Scalar)
- void validate()const {
- SPIRVInstruction::validate();
- if (getValue(Vector)->isForward() ||
- getValue(Scalar)->isForward())
- return;
-
- assert(getValueType(Vector)->isTypeVector() &&
- getValueType(Vector)->getVectorComponentType()->isTypeFloat() &&
- "First operand must be a vector of floating-point type");
- assert(getValueType(getId())->isTypeVector() &&
- getValueType(getId())->getVectorComponentType()->isTypeFloat() &&
- "Result type must be a vector of floating-point type");
- assert(getValueType(Vector)->getVectorComponentType() ==
- getValueType(getId())->getVectorComponentType() &&
- "Scalar must have the same type as the Component Type in Result Type");
- SPIRVInstruction::validate();
- }
-protected:
- SPIRVId Vector;
- SPIRVId Scalar;
-};
-
-class SPIRVUnary:public SPIRVInstTemplateBase {
-protected:
- void validate()const {
- auto Op = Ops[0];
- SPIRVInstruction::validate();
- if (getValue(Op)->isForward())
- return;
- if (isGenericNegateOpCode(OpCode)) {
- SPIRVType *resTy = Type->isTypeVector() ?
- Type->getVectorComponentType() : Type;
- SPIRVType *opTy = Type->isTypeVector() ?
- getValueType(Op)->getVectorComponentType() : getValueType(Op);
-
+ assert(conTy->isTypeBool() && "Invalid type"); + assert(getType() == getValueType(Op1) && getType() == getValueType(Op2) && + "Inconsistent type"); + } + SPIRVId Condition; + SPIRVId Op1; + SPIRVId Op2; +}; + +class SPIRVSelectionMerge: public SPIRVInstruction { +public: + static const Op OC = OpSelectionMerge; + static const SPIRVWord FixedWordCount = 3; + + SPIRVSelectionMerge(SPIRVId TheMergeBlock, + SPIRVWord TheSelectionControl, SPIRVBasicBlock *BB) + :SPIRVInstruction(3, OC, BB), MergeBlock(TheMergeBlock), + SelectionControl(TheSelectionControl) { + validate(); + assert(BB && "Invalid BB"); + } + + SPIRVSelectionMerge() :SPIRVInstruction(OC), MergeBlock(SPIRVID_INVALID), + SelectionControl(SPIRVWORD_MAX) { + setHasNoId(); + setHasNoType(); + } + + SPIRVId getMergeBlock() { return MergeBlock; } + SPIRVWord getSelectionControl() { return SelectionControl; } + + _SPIRV_DEF_ENCDEC2(MergeBlock, SelectionControl) + +protected: + SPIRVId MergeBlock; + SPIRVWord SelectionControl; +}; + +class SPIRVLoopMerge : public SPIRVInstruction { +public: + static const Op OC = OpLoopMerge; + static const SPIRVWord FixedWordCount = 4; + + SPIRVLoopMerge(SPIRVId TheMergeBlock, SPIRVId TheContinueTarget, + SPIRVWord TheLoopControl, SPIRVBasicBlock *BB) + :SPIRVInstruction(FixedWordCount, OC, BB), MergeBlock(TheMergeBlock), + ContinueTarget(TheContinueTarget), LoopControl(TheLoopControl) { + validate(); + assert(BB && "Invalid BB"); + } + + SPIRVLoopMerge() : SPIRVInstruction(OC), MergeBlock(SPIRVID_MAX), + LoopControl(SPIRVWORD_MAX) { + setHasNoId(); + setHasNoType(); + } + + SPIRVId getMergeBlock() { return MergeBlock; } + SPIRVId getContinueTarget() { return ContinueTarget; } + SPIRVWord getLoopControl() { return LoopControl; } + _SPIRV_DEF_ENCDEC3(MergeBlock, ContinueTarget, LoopControl) + +protected: + SPIRVId MergeBlock; + SPIRVId ContinueTarget; + SPIRVWord LoopControl; +}; + +class SPIRVSwitch: public SPIRVInstruction { +public: + static const Op OC = OpSwitch; + static const SPIRVWord FixedWordCount = 3; + typedef std::vector<SPIRVWord> LiteralTy; + typedef std::pair<LiteralTy, SPIRVBasicBlock *> PairTy; + + SPIRVSwitch(SPIRVValue *TheSelect, SPIRVBasicBlock *TheDefault, + const std::vector<PairTy> &ThePairs, + SPIRVBasicBlock *BB) + :SPIRVInstruction(ThePairs.size() * (ThePairs.at(0).first.size() + 1) + FixedWordCount, OC, BB), + Select(TheSelect->getId()), Default(TheDefault->getId()) { + + for (auto &I : ThePairs) { + for (auto &U : I.first) + Pairs.push_back(U); + Pairs.push_back(I.second->getId()); + } + validate(); + assert(BB && "Invalid BB"); + } + SPIRVSwitch():SPIRVInstruction(OC), Select(SPIRVWORD_MAX), + Default(SPIRVWORD_MAX) { + setHasNoId(); + setHasNoType(); + } + std::vector<SPIRVValue *> getPairs() { + return getValues(Pairs); + } + SPIRVValue *getSelect() const { return getValue(Select);} + SPIRVBasicBlock *getDefault() const { + return static_cast<SPIRVBasicBlock *>(getValue(Default)); + } + size_t getLiteralsCount() const { return getSelect()->getType()->getBitWidth() / (sizeof(SPIRVWord) * 8);} + size_t getPairSize() const { return getLiteralsCount() + 1; } + size_t getNumPairs() const { return Pairs.size()/getPairSize();} + void foreachPair(std::function<void(LiteralTy, SPIRVBasicBlock *)> Func) + const { + unsigned PairSize = getPairSize(); + for (size_t I = 0, E = getNumPairs(); I != E; ++I) { + SPIRVEntry *BB; + LiteralTy Literals; + if (!Module->exist(Pairs[PairSize*I + getLiteralsCount()], &BB)) + continue; + + for (size_t i = 0; i < getLiteralsCount(); ++i) { + Literals.push_back(Pairs.at(PairSize*I + i)); + } + Func(Literals, static_cast<SPIRVBasicBlock *>(BB)); + } + } + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + Pairs.resize(TheWordCount - FixedWordCount); + } + _SPIRV_DEF_ENCDEC3(Select, Default, Pairs) + void validate()const { + assert(WordCount == Pairs.size() + FixedWordCount); + assert(OpCode == OC); + assert(Pairs.size() % getPairSize() == 0); + foreachPair([=](LiteralTy Literals, SPIRVBasicBlock *BB){ + assert(BB->isBasicBlock() || BB->isForward()); + }); + SPIRVInstruction::validate(); + } +protected: + SPIRVId Select; + SPIRVId Default; + std::vector<SPIRVWord> Pairs; +}; + +class SPIRVFMod : public SPIRVInstruction { +public: + static const Op OC = OpFMod; + static const SPIRVWord FixedWordCount = 4; + // Complete constructor + SPIRVFMod(SPIRVType *TheType, SPIRVId TheId, SPIRVId TheDividend, + SPIRVId TheDivisor, SPIRVBasicBlock *BB) + :SPIRVInstruction(5, OC, TheType, TheId, BB), Dividend(TheDividend), Divisor(TheDivisor) { + validate(); + assert(BB && "Invalid BB"); + } + // Incomplete constructor + SPIRVFMod() :SPIRVInstruction(OC), Dividend(SPIRVID_INVALID), + Divisor(SPIRVID_INVALID) { + } + SPIRVValue *getDividend() const { return getValue(Dividend); } + SPIRVValue *getDivisor() const { return getValue(Divisor); } + + std::vector<SPIRVValue*> getOperands() { + std::vector<SPIRVId> Operands; + Operands.push_back(Dividend); + Operands.push_back(Divisor); + return getValues(Operands); + } + + void setWordCount(SPIRVWord FixedWordCount) { + SPIRVEntry::setWordCount(FixedWordCount); + } + _SPIRV_DEF_ENCDEC4(Type, Id, Dividend, Divisor) + void validate()const { + SPIRVInstruction::validate(); + if (getValue(Dividend)->isForward() || + getValue(Divisor)->isForward()) + return; + SPIRVInstruction::validate(); + } +protected: + SPIRVId Dividend; + SPIRVId Divisor; +}; + +class SPIRVVectorTimesScalar : public SPIRVInstruction { +public: + static const Op OC = OpVectorTimesScalar; + static const SPIRVWord FixedWordCount = 4; + // Complete constructor + SPIRVVectorTimesScalar(SPIRVType *TheType, SPIRVId TheId, SPIRVId TheVector, + SPIRVId TheScalar, SPIRVBasicBlock *BB) + :SPIRVInstruction(5, OC, TheType, TheId, BB), Vector(TheVector), Scalar(TheScalar) { + validate(); + assert(BB && "Invalid BB"); + } + // Incomplete constructor + SPIRVVectorTimesScalar() :SPIRVInstruction(OC), Vector(SPIRVID_INVALID), + Scalar(SPIRVID_INVALID) { + } + SPIRVValue *getVector() const { return getValue(Vector); } + SPIRVValue *getScalar() const { return getValue(Scalar); } + + std::vector<SPIRVValue*> getOperands() { + std::vector<SPIRVId> Operands; + Operands.push_back(Vector); + Operands.push_back(Scalar); + return getValues(Operands); + } + + void setWordCount(SPIRVWord FixedWordCount) { + SPIRVEntry::setWordCount(FixedWordCount); + } + _SPIRV_DEF_ENCDEC4(Type, Id, Vector, Scalar) + void validate()const { + SPIRVInstruction::validate(); + if (getValue(Vector)->isForward() || + getValue(Scalar)->isForward()) + return; + + assert(getValueType(Vector)->isTypeVector() && + getValueType(Vector)->getVectorComponentType()->isTypeFloat() && + "First operand must be a vector of floating-point type"); + assert(getValueType(getId())->isTypeVector() && + getValueType(getId())->getVectorComponentType()->isTypeFloat() && + "Result type must be a vector of floating-point type"); + assert(getValueType(Vector)->getVectorComponentType() == + getValueType(getId())->getVectorComponentType() && + "Scalar must have the same type as the Component Type in Result Type"); + SPIRVInstruction::validate(); + } +protected: + SPIRVId Vector; + SPIRVId Scalar; +}; + +class SPIRVUnary:public SPIRVInstTemplateBase { +protected: + void validate()const { + auto Op = Ops[0]; + SPIRVInstruction::validate(); + if (getValue(Op)->isForward()) + return; + if (isGenericNegateOpCode(OpCode)) { + SPIRVType *resTy = Type->isTypeVector() ? + Type->getVectorComponentType() : Type; + SPIRVType *opTy = Type->isTypeVector() ? + getValueType(Op)->getVectorComponentType() : getValueType(Op); + (void)resTy; (void)opTy; - assert(getType() == getValueType(Op) &&
- "Inconsistent type");
- assert((resTy->isTypeInt() || resTy->isTypeFloat()) &&
- "Invalid type for Generic Negate instruction");
- assert((resTy->getBitWidth() == opTy->getBitWidth()) &&
- "Invalid bitwidth for Generic Negate instruction");
- assert((Type->isTypeVector() ? (Type->getVectorComponentCount() ==
- getValueType(Op)->getVectorComponentCount()): 1) &&
- "Invalid vector component Width for Generic Negate instruction");
- }
- }
-};
-
-template<Op OC>
-class SPIRVUnaryInst:public SPIRVInstTemplate<SPIRVUnary, OC, true, 4, false> {
-};
-
-#define _SPIRV_OP(x) typedef SPIRVUnaryInst<Op##x> SPIRV##x;
-_SPIRV_OP(ConvertFToU)
-_SPIRV_OP(ConvertFToS)
-_SPIRV_OP(ConvertSToF)
-_SPIRV_OP(ConvertUToF)
-_SPIRV_OP(UConvert)
-_SPIRV_OP(SConvert)
-_SPIRV_OP(FConvert)
-_SPIRV_OP(SatConvertSToU)
-_SPIRV_OP(SatConvertUToS)
-_SPIRV_OP(ConvertPtrToU)
-_SPIRV_OP(ConvertUToPtr)
-_SPIRV_OP(PtrCastToGeneric)
-_SPIRV_OP(GenericCastToPtr)
-_SPIRV_OP(Bitcast)
-_SPIRV_OP(SNegate)
-_SPIRV_OP(FNegate)
-_SPIRV_OP(Not)
-_SPIRV_OP(LogicalNot)
-_SPIRV_OP(IsNan)
-_SPIRV_OP(IsInf)
-_SPIRV_OP(IsFinite)
-_SPIRV_OP(IsNormal)
-_SPIRV_OP(SignBitSet)
-_SPIRV_OP(Any)
-_SPIRV_OP(All)
-#undef _SPIRV_OP
-
-class SPIRVAccessChainBase :public SPIRVInstTemplateBase {
-public:
- SPIRVValue *getBase() { return this->getValue(this->Ops[0]);}
- std::vector<SPIRVValue *> getIndices()const {
- std::vector<SPIRVWord> IndexWords(this->Ops.begin() + 1, this->Ops.end());
- return this->getValues(IndexWords);
- }
- bool isInBounds() {
- return OpCode == OpInBoundsAccessChain ||
- OpCode == OpInBoundsPtrAccessChain;
- }
- bool hasPtrIndex() {
- return OpCode == OpPtrAccessChain ||
- OpCode == OpInBoundsPtrAccessChain;
- }
-};
-
-template<Op OC, unsigned FixedWC>
-class SPIRVAccessChainGeneric
- :public SPIRVInstTemplate<SPIRVAccessChainBase, OC, true, FixedWC, true> {
-};
-
-typedef SPIRVAccessChainGeneric<OpAccessChain, 4> SPIRVAccessChain;
-typedef SPIRVAccessChainGeneric<OpInBoundsAccessChain, 4>
- SPIRVInBoundsAccessChain;
-typedef SPIRVAccessChainGeneric<OpPtrAccessChain, 5> SPIRVPtrAccessChain;
-typedef SPIRVAccessChainGeneric<OpInBoundsPtrAccessChain, 5>
- SPIRVInBoundsPtrAccessChain;
-
-template<Op OC, SPIRVWord FixedWordCount>
-class SPIRVFunctionCallGeneric: public SPIRVInstruction {
-public:
- SPIRVFunctionCallGeneric(SPIRVType *TheType, SPIRVId TheId,
- const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB)
- :SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, TheId, BB),
- Args(TheArgs){
- validate();
- assert(BB && "Invalid BB");
- }
- SPIRVFunctionCallGeneric(SPIRVType *TheType, SPIRVId TheId,
- const std::vector<SPIRVValue *> &TheArgs, SPIRVBasicBlock *BB)
- :SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, TheId, BB) {
- Args = getIds(TheArgs);
- validate();
- assert(BB && "Invalid BB");
- }
- SPIRVFunctionCallGeneric():SPIRVInstruction(OC) {}
- const std::vector<SPIRVWord> &getArguments() {
- return Args;
- }
- std::vector<SPIRVValue *> getArgumentValues() {
- return getValues(Args);
- }
- std::vector<SPIRVType *> getArgumentValueTypes()const {
- std::vector<SPIRVType *> ArgTypes;
- for (auto &I:Args)
- ArgTypes.push_back(getValue(I)->getType());
- return ArgTypes;
- }
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- Args.resize(TheWordCount - FixedWordCount);
- }
- void validate()const {
- SPIRVInstruction::validate();
- }
-protected:
- std::vector<SPIRVWord> Args;
-};
-
-class SPIRVFunctionCall:
- public SPIRVFunctionCallGeneric<OpFunctionCall, 4> {
-public:
- SPIRVFunctionCall(SPIRVId TheId, SPIRVFunction *TheFunction,
- const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB);
- SPIRVFunctionCall():FunctionId(SPIRVID_INVALID) {}
- SPIRVFunction *getFunction()const {
- return get<SPIRVFunction>(FunctionId);
- }
- _SPIRV_DEF_ENCDEC4(Type, Id, FunctionId, Args)
- void validate()const;
- bool isOperandLiteral(unsigned Index) const { return false;}
-protected:
- SPIRVId FunctionId;
-};
-
-class SPIRVExtInst: public SPIRVFunctionCallGeneric<OpExtInst, 5> {
-public:
- SPIRVExtInst(SPIRVType *TheType, SPIRVId TheId,
- SPIRVId TheBuiltinSet, SPIRVWord TheEntryPoint,
- const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB)
- :SPIRVFunctionCallGeneric(TheType, TheId, TheArgs, BB),
- ExtSetId(TheBuiltinSet),
- ExtOp(TheEntryPoint) {
- setExtSetKindById();
- validate();
- }
- SPIRVExtInst(SPIRVType *TheType, SPIRVId TheId,
- SPIRVId TheBuiltinSet, SPIRVWord TheEntryPoint,
- const std::vector<SPIRVValue *> &TheArgs, SPIRVBasicBlock *BB)
- :SPIRVFunctionCallGeneric(TheType, TheId, TheArgs, BB),
- ExtSetId(TheBuiltinSet),
- ExtOp(TheEntryPoint) {
- setExtSetKindById();
- validate();
- }
- SPIRVExtInst(SPIRVExtInstSetKind SetKind = SPIRVEIS_Count,
- unsigned ExtOC = SPIRVWORD_MAX)
- :ExtSetId(SPIRVWORD_MAX), ExtOp(ExtOC), ExtSetKind(SetKind) {}
- void setExtSetId(unsigned Set) { ExtSetId = Set;}
- void setExtOp(unsigned ExtOC) { ExtOp = ExtOC;}
- SPIRVId getExtSetId()const {
- return ExtSetId;
- }
- SPIRVWord getExtOp()const {
- return ExtOp;
- }
- void setExtSetKindById() {
- assert(Module && "Invalid module");
- ExtSetKind = Module->getBuiltinSet(ExtSetId);
- assert(ExtSetKind == SPIRVEIS_OpenCL && "not supported");
- }
- void encode(spv_ostream &O) const {
- getEncoder(O) << Type << Id << ExtSetId;
- switch(ExtSetKind) {
- case SPIRVEIS_OpenCL:
- getEncoder(O) << ExtOpOCL;
- break;
- default:
- assert(0 && "not supported");
- getEncoder(O) << ExtOp;
- }
- getEncoder(O) << Args;
- }
- void decode(std::istream &I) {
- getDecoder(I) >> Type >> Id >> ExtSetId;
- setExtSetKindById();
- switch(ExtSetKind) {
- case SPIRVEIS_OpenCL:
- getDecoder(I) >> ExtOpOCL;
- break;
- default:
- assert(0 && "not supported");
- getDecoder(I) >> ExtOp;
- }
- getDecoder(I) >> Args;
- }
- void validate()const {
- SPIRVFunctionCallGeneric::validate();
- validateBuiltin(ExtSetId, ExtOp);
- }
- bool isOperandLiteral(unsigned Index) const {
- assert(ExtSetKind == SPIRVEIS_OpenCL &&
- "Unsupported extended instruction set");
- auto EOC = static_cast<OCLExtOpKind>(ExtOp);
- switch(EOC) {
- default:
- return false;
- case OpenCLLIB::Vloadn:
- case OpenCLLIB::Vload_halfn:
- case OpenCLLIB::Vloada_halfn:
- return Index == 2;
- case OpenCLLIB::Vstore_half_r:
- case OpenCLLIB::Vstore_halfn_r:
- case OpenCLLIB::Vstorea_halfn_r:
- return Index == 3;
- }
- }
-protected:
- SPIRVId ExtSetId;
- union {
- SPIRVWord ExtOp;
- OCLExtOpKind ExtOpOCL;
- };
- SPIRVExtInstSetKind ExtSetKind;
-};
-
-class SPIRVCompositeConstruct : public SPIRVInstruction {
-public:
- const static Op OC = OpCompositeConstruct;
- const static SPIRVWord FixedWordCount = 3;
- // Complete constructor
- SPIRVCompositeConstruct(SPIRVType *TheType, SPIRVId TheId,
- const std::vector<SPIRVId>& TheConstituents, SPIRVBasicBlock *TheBB) :
- SPIRVInstruction(TheConstituents.size() + FixedWordCount, OC,
- TheType, TheId, TheBB), Constituents(TheConstituents) {
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVCompositeConstruct():SPIRVInstruction(OC) {}
-
- const std::vector<SPIRVValue*> getConstituents() const {
- return getValues(Constituents);
- }
-protected:
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- Constituents.resize(TheWordCount - FixedWordCount);
- }
- _SPIRV_DEF_ENCDEC3(Type, Id, Constituents)
- void validate() const {
- SPIRVInstruction::validate();
- switch (getValueType(this->getId())->getOpCode()) {
- case OpTypeVector:
- assert(getConstituents().size() > 1 &&
- "There must be at least two Constituent operands in vector");
- case OpTypeArray:
- case OpTypeStruct:
- break;
- default:
- assert("Invalid type");
- }
- }
- std::vector<SPIRVId> Constituents;
-};
-
-class SPIRVCompositeExtract:public SPIRVInstruction {
-public:
- const static Op OC = OpCompositeExtract;
- // Complete constructor
- SPIRVCompositeExtract(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheComposite,
- const std::vector<SPIRVWord>& TheIndices, SPIRVBasicBlock *TheBB):
- SPIRVInstruction(TheIndices.size() + 4, OC, TheType, TheId, TheBB),
- Composite(TheComposite->getId()), Indices(TheIndices){
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVCompositeExtract():SPIRVInstruction(OC), Composite(SPIRVID_INVALID){}
-
- SPIRVValue *getComposite() { return getValue(Composite);}
- const std::vector<SPIRVWord>& getIndices()const { return Indices;}
-protected:
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- Indices.resize(TheWordCount - 4);
- }
- _SPIRV_DEF_ENCDEC4(Type, Id, Composite, Indices)
- // ToDo: validate the result type is consistent with the base type and indices
- // need to trace through the base type for struct types
- void validate()const {
- SPIRVInstruction::validate();
- assert(getValueType(Composite)->isTypeArray() ||
- getValueType(Composite)->isTypeStruct() ||
- getValueType(Composite)->isTypeVector());
- }
- SPIRVId Composite;
- std::vector<SPIRVWord> Indices;
-};
-
-class SPIRVCompositeInsert:public SPIRVInstruction {
-public:
- const static Op OC = OpCompositeInsert;
- const static SPIRVWord FixedWordCount = 5;
- // Complete constructor
- SPIRVCompositeInsert(SPIRVId TheId, SPIRVValue *TheObject,
- SPIRVValue *TheComposite, const std::vector<SPIRVWord>& TheIndices,
- SPIRVBasicBlock *TheBB):
- SPIRVInstruction(TheIndices.size() + FixedWordCount, OC,
- TheComposite->getType(), TheId, TheBB),
- Object(TheObject->getId()), Composite(TheComposite->getId()),
- Indices(TheIndices){
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVCompositeInsert():SPIRVInstruction(OC), Object(SPIRVID_INVALID),
- Composite(SPIRVID_INVALID){}
-
- SPIRVValue *getObject() { return getValue(Object);}
- SPIRVValue *getComposite() { return getValue(Composite);}
- const std::vector<SPIRVWord>& getIndices()const { return Indices;}
-protected:
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- Indices.resize(TheWordCount - FixedWordCount);
- }
- _SPIRV_DEF_ENCDEC5(Type, Id, Object, Composite, Indices)
- // ToDo: validate the object type is consistent with the base type and indices
- // need to trace through the base type for struct types
- void validate()const {
- SPIRVInstruction::validate();
- assert(OpCode == OC);
- assert(WordCount == Indices.size() + FixedWordCount);
- assert(getValueType(Composite)->isTypeArray() ||
- getValueType(Composite)->isTypeStruct() ||
- getValueType(Composite)->isTypeVector());
- assert(Type == getValueType(Composite));
- }
- SPIRVId Object;
- SPIRVId Composite;
- std::vector<SPIRVWord> Indices;
-};
-
-class SPIRVCopyObject :public SPIRVInstruction {
-public:
- const static Op OC = OpCopyObject;
-
- // Complete constructor
- SPIRVCopyObject(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheOperand,
- SPIRVBasicBlock *TheBB) :
- SPIRVInstruction(4, OC, TheType, TheId, TheBB),
- Operand(TheOperand->getId()) {
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVCopyObject() :SPIRVInstruction(OC), Operand(SPIRVID_INVALID) {}
-
- SPIRVValue *getOperand() { return getValue(Operand); }
-
-protected:
- _SPIRV_DEF_ENCDEC3(Type, Id, Operand)
-
- void validate()const {
- SPIRVInstruction::validate();
- }
- SPIRVId Operand;
-};
-
-
-class SPIRVCopyMemory :public SPIRVInstruction, public SPIRVMemoryAccess {
-public:
- const static Op OC = OpCopyMemory;
- const static SPIRVWord FixedWords = 3;
- // Complete constructor
- SPIRVCopyMemory(SPIRVValue *TheTarget, SPIRVValue *TheSource,
- const std::vector<SPIRVWord> &TheMemoryAccess,
- SPIRVBasicBlock *TheBB) :
- SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OC, TheBB),
- SPIRVMemoryAccess(TheMemoryAccess),
- MemoryAccess(TheMemoryAccess),
- Target(TheTarget->getId()),
- Source(TheSource->getId()) {
- validate();
- assert(TheBB && "Invalid BB");
- }
-
- // Incomplete constructor
- SPIRVCopyMemory() :SPIRVInstruction(OC), SPIRVMemoryAccess(),
- Target(SPIRVID_INVALID),
- Source(SPIRVID_INVALID) {
- setHasNoId();
- setHasNoType();
- }
-
- SPIRVValue *getSource() { return getValue(Source); }
- SPIRVValue *getTarget() { return getValue(Target); }
-
-protected:
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- MemoryAccess.resize(TheWordCount - FixedWords);
- }
-
- void encode(spv_ostream &O) const {
- getEncoder(O) << Target << Source << MemoryAccess;
- }
-
- void decode(std::istream &I) {
- getDecoder(I) >> Target >> Source >> MemoryAccess;
- MemoryAccessUpdate(MemoryAccess);
- }
-
- void validate()const {
- assert((getValueType(Id) == getValueType(Source)) && "Inconsistent type");
- assert(getValueType(Id)->isTypePointer() && "Invalid type");
- assert(!(getValueType(Id)->getPointerElementType()->isTypeVoid()) &&
- "Invalid type");
- SPIRVInstruction::validate();
- }
-
- std::vector<SPIRVWord> MemoryAccess;
- SPIRVId Target;
- SPIRVId Source;
-};
-
-class SPIRVCopyMemorySized :public SPIRVInstruction, public SPIRVMemoryAccess {
-public:
- const static Op OC = OpCopyMemorySized;
- const static SPIRVWord FixedWords = 4;
- // Complete constructor
- SPIRVCopyMemorySized(SPIRVValue *TheTarget, SPIRVValue *TheSource,
- SPIRVValue *TheSize, const std::vector<SPIRVWord> &TheMemoryAccess,
- SPIRVBasicBlock *TheBB) :
- SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OC, TheBB),
- SPIRVMemoryAccess(TheMemoryAccess),
- MemoryAccess(TheMemoryAccess),
- Target(TheTarget->getId()),
- Source(TheSource->getId()),
- Size(TheSize->getId()) {
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVCopyMemorySized() :SPIRVInstruction(OC), SPIRVMemoryAccess(),
- Target(SPIRVID_INVALID), Source(SPIRVID_INVALID), Size(0) {
- setHasNoId();
- setHasNoType();
- }
-
- SPIRVValue *getSource() { return getValue(Source); }
- SPIRVValue *getTarget() { return getValue(Target); }
- SPIRVValue *getSize() { return getValue(Size); }
-
-protected:
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- MemoryAccess.resize(TheWordCount - FixedWords);
- }
-
- void encode(spv_ostream &O) const {
- getEncoder(O) << Target << Source << Size << MemoryAccess;
- }
-
- void decode(std::istream &I) {
- getDecoder(I) >> Target >> Source >> Size >> MemoryAccess;
- MemoryAccessUpdate(MemoryAccess);
- }
-
- void validate()const {
- SPIRVInstruction::validate();
- }
-
- std::vector<SPIRVWord> MemoryAccess;
- SPIRVId Target;
- SPIRVId Source;
- SPIRVId Size;
-};
-
-class SPIRVVectorExtractDynamic:public SPIRVInstruction {
-public:
- const static Op OC = OpVectorExtractDynamic;
- // Complete constructor
- SPIRVVectorExtractDynamic(SPIRVId TheId, SPIRVValue *TheVector,
- SPIRVValue* TheIndex, SPIRVBasicBlock *TheBB)
- :SPIRVInstruction(5, OC, TheVector->getType()->getVectorComponentType(),
- TheId, TheBB), VectorId(TheVector->getId()),
- IndexId(TheIndex->getId()){
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVVectorExtractDynamic():SPIRVInstruction(OC), VectorId(SPIRVID_INVALID),
- IndexId(SPIRVID_INVALID){}
-
- SPIRVValue *getVector() { return getValue(VectorId);}
- SPIRVValue *getIndex()const { return getValue(IndexId);}
-protected:
- _SPIRV_DEF_ENCDEC4(Type, Id, VectorId, IndexId)
- void validate()const {
- SPIRVInstruction::validate();
- if (getValue(VectorId)->isForward())
- return;
- assert(getValueType(VectorId)->isTypeVector());
- }
- SPIRVId VectorId;
- SPIRVId IndexId;
-};
-
-class SPIRVVectorInsertDynamic :public SPIRVInstruction {
-public:
- const static Op OC = OpVectorInsertDynamic;
- // Complete constructor
- SPIRVVectorInsertDynamic(SPIRVId TheId, SPIRVValue *TheVector,
- SPIRVValue* TheComponent, SPIRVValue* TheIndex, SPIRVBasicBlock *TheBB)
- :SPIRVInstruction(6, OC, TheVector->getType()->getVectorComponentType(),
- TheId, TheBB), VectorId(TheVector->getId()),
- IndexId(TheIndex->getId()), ComponentId(TheComponent->getId()){
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVVectorInsertDynamic() :SPIRVInstruction(OC), VectorId(SPIRVID_INVALID),
- IndexId(SPIRVID_INVALID), ComponentId(SPIRVID_INVALID){}
-
- SPIRVValue *getVector() { return getValue(VectorId); }
- SPIRVValue *getIndex()const { return getValue(IndexId); }
- SPIRVValue *getComponent() { return getValue(ComponentId); }
-protected:
- _SPIRV_DEF_ENCDEC5(Type, Id, VectorId, ComponentId, IndexId)
- void validate()const {
- SPIRVInstruction::validate();
- if (getValue(VectorId)->isForward())
- return;
- assert(getValueType(VectorId)->isTypeVector());
- }
- SPIRVId VectorId;
- SPIRVId IndexId;
- SPIRVId ComponentId;
-};
-
-class SPIRVVectorShuffle:public SPIRVInstruction {
-public:
- const static Op OC = OpVectorShuffle;
- const static SPIRVWord FixedWordCount = 5;
- // Complete constructor
- SPIRVVectorShuffle(SPIRVId TheId, SPIRVType *TheType, SPIRVValue *TheVector1,
- SPIRVValue *TheVector2, const std::vector<SPIRVWord>& TheComponents,
- SPIRVBasicBlock *TheBB):
- SPIRVInstruction(TheComponents.size() + FixedWordCount, OC, TheType,
- TheId, TheBB),
- Vector1(TheVector1->getId()), Vector2(TheVector2->getId()),
- Components(TheComponents){
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVVectorShuffle():SPIRVInstruction(OC), Vector1(SPIRVID_INVALID),
- Vector2(SPIRVID_INVALID){}
-
- SPIRVValue *getVector1() { return getValue(Vector1);}
- SPIRVValue *getVector2() { return getValue(Vector2);}
- const std::vector<SPIRVWord>& getComponents()const { return Components;}
-protected:
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- Components.resize(TheWordCount - FixedWordCount);
- }
- _SPIRV_DEF_ENCDEC5(Type, Id, Vector1, Vector2, Components)
- void validate()const {
- SPIRVInstruction::validate();
- assert(OpCode == OC);
- assert(WordCount == Components.size() + FixedWordCount);
- assert(Type->isTypeVector());
- assert(Type->getVectorComponentType() ==
- getValueType(Vector1)->getVectorComponentType());
- if (getValue(Vector1)->isForward() ||
- getValue(Vector2)->isForward())
- return;
- assert(getValueType(Vector1) == getValueType(Vector2));
- assert(Components.size() == Type->getVectorComponentCount());
- assert(Components.size() > 1);
- }
- SPIRVId Vector1;
- SPIRVId Vector2;
- std::vector<SPIRVWord> Components;
-};
-
-class SPIRVControlBarrier:public SPIRVInstruction {
-public:
- static const Op OC = OpControlBarrier;
- // Complete constructor
- SPIRVControlBarrier(SPIRVValue *TheScope,
- SPIRVValue *TheMemScope, SPIRVValue *TheMemSema,
- SPIRVBasicBlock *TheBB)
- :SPIRVInstruction(4, OC, TheBB), ExecScope(TheScope->getId()),
- MemScope(TheMemScope->getId()), MemSema(TheMemSema->getId()){
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVControlBarrier():SPIRVInstruction(OC), ExecScope(ScopeInvocation) {
- setHasNoId();
- setHasNoType();
- }
- void setWordCount(SPIRVWord TheWordCount) {
- SPIRVEntry::setWordCount(TheWordCount);
- }
- SPIRVValue *getExecScope() const { return getValue(ExecScope); }
- SPIRVValue *getMemScope() const { return getValue(MemScope); }
- SPIRVValue *getMemSemantic() const { return getValue(MemSema); }
- std::vector<SPIRVValue *> getOperands() {
- std::vector<SPIRVId> Operands;
- Operands.push_back(ExecScope);
- Operands.push_back(MemScope);
- Operands.push_back(MemSema);
- return getValues(Operands);
- }
-protected:
- _SPIRV_DEF_ENCDEC3(ExecScope, MemScope, MemSema)
- void validate()const {
- assert(OpCode == OC);
- assert(WordCount == 4);
- SPIRVInstruction::validate();
- }
- SPIRVId ExecScope;
- SPIRVId MemScope;
- SPIRVId MemSema;
-};
-
-template<Op OC>
-class SPIRVLifetime : public SPIRVInstruction {
-public:
- // Complete constructor
- SPIRVLifetime(SPIRVId TheObject, SPIRVWord TheSize,
- SPIRVBasicBlock *TheBB) :
- SPIRVInstruction(3, OC, TheBB), Object(TheObject), Size(TheSize) {
- validate();
- assert(TheBB && "Invalid BB");
- };
- // Incomplete constructor
- SPIRVLifetime() :SPIRVInstruction(OC), Object(SPIRVID_INVALID),
- Size(SPIRVWORD_MAX) {
- setHasNoId();
- setHasNoType();
- }
- SPIRVCapVec getRequiredCapability() const override {
- return getVec(CapabilityKernel);
- }
- SPIRVValue *getObject() { return getValue(Object); };
- SPIRVWord getSize() { return Size; };
-protected:
- void validate() const {
- auto Obj = static_cast<SPIRVVariable*>(getValue(Object));
- assert(Obj->getStorageClass() == StorageClassFunction &&
- "Invalid storage class");
- assert(Obj->getType()->isTypePointer() &&
- "Objects type must be a pointer");
- if (!Obj->getType()->getPointerElementType()->isTypeVoid() ||
- !Module->hasCapability(CapabilityAddresses))
- assert(Size == 0 && "Size must be 0");
- }
- _SPIRV_DEF_ENCDEC2(Object, Size)
- SPIRVId Object;
- SPIRVWord Size;
-};
-
-typedef SPIRVLifetime<OpLifetimeStart> SPIRVLifetimeStart;
-typedef SPIRVLifetime<OpLifetimeStop> SPIRVLifetimeStop;
-
-class SPIRVGroupAsyncCopy:public SPIRVInstruction {
-public:
- static const Op OC = OpGroupAsyncCopy;
- static const SPIRVWord WC = 9;
- // Complete constructor
- SPIRVGroupAsyncCopy(SPIRVValue *TheScope, SPIRVId TheId,
- SPIRVValue *TheDest, SPIRVValue *TheSrc, SPIRVValue *TheNumElems,
- SPIRVValue *TheStride, SPIRVValue *TheEvent, SPIRVBasicBlock *TheBB)
- :SPIRVInstruction(WC, OC, TheEvent->getType(), TheId, TheBB),
- ExecScope(TheScope->getId()), Destination(TheDest->getId()),
- Source(TheSrc->getId()), NumElements(TheNumElems->getId()),
- Stride(TheStride->getId()), Event(TheEvent->getId()){
- validate();
- assert(TheBB && "Invalid BB");
- }
- // Incomplete constructor
- SPIRVGroupAsyncCopy():SPIRVInstruction(OC), ExecScope(SPIRVID_INVALID),
- Destination(SPIRVID_INVALID), Source(SPIRVID_INVALID),
- NumElements(SPIRVID_INVALID), Stride(SPIRVID_INVALID),
- Event(SPIRVID_INVALID){
- }
- SPIRVValue *getExecScope() const { return getValue(ExecScope); }
- SPIRVValue *getDestination()const { return getValue(Destination);}
- SPIRVValue *getSource()const { return getValue(Source);}
- SPIRVValue *getNumElements()const { return getValue(NumElements);}
- SPIRVValue *getStride()const { return getValue(Stride);}
- SPIRVValue *getEvent()const { return getValue(Event);}
- std::vector<SPIRVValue *> getOperands() {
- std::vector<SPIRVId> Operands;
- Operands.push_back(Destination);
- Operands.push_back(Source);
- Operands.push_back(NumElements);
- Operands.push_back(Stride);
- Operands.push_back(Event);
- return getValues(Operands);
- }
-
-protected:
- _SPIRV_DEF_ENCDEC8(Type, Id, ExecScope, Destination, Source, NumElements,
- Stride, Event)
- void validate()const {
- assert(OpCode == OC);
- assert(WordCount == WC);
- SPIRVInstruction::validate();
- }
- SPIRVId ExecScope;
- SPIRVId Destination;
- SPIRVId Source;
- SPIRVId NumElements;
- SPIRVId Stride;
- SPIRVId Event;
-};
-
-enum SPIRVOpKind {
- SPIRVOPK_Id,
- SPIRVOPK_Literal,
- SPIRVOPK_Count
-};
-
-class SPIRVDevEnqInstBase:public SPIRVInstTemplateBase {
-public:
- SPIRVCapVec getRequiredCapability() const override {
- return getVec(CapabilityDeviceEnqueue);
- }
-};
-
-#define _SPIRV_OP(x, ...) \
- typedef SPIRVInstTemplate<SPIRVDevEnqInstBase, Op##x, __VA_ARGS__> \
- SPIRV##x;
-// CL 2.0 enqueue kernel builtins
-_SPIRV_OP(EnqueueMarker, true, 7)
-_SPIRV_OP(EnqueueKernel, true, 13, true)
-_SPIRV_OP(GetKernelNDrangeSubGroupCount, true, 8)
-_SPIRV_OP(GetKernelNDrangeMaxSubGroupSize, true, 8)
-_SPIRV_OP(GetKernelWorkGroupSize, true, 7)
-_SPIRV_OP(GetKernelPreferredWorkGroupSizeMultiple, true, 7)
-_SPIRV_OP(RetainEvent, false, 2)
-_SPIRV_OP(ReleaseEvent, false, 2)
-_SPIRV_OP(CreateUserEvent, true, 3)
-_SPIRV_OP(IsValidEvent, true, 4)
-_SPIRV_OP(SetUserEventStatus, false, 3)
-_SPIRV_OP(CaptureEventProfilingInfo, false, 4)
-_SPIRV_OP(GetDefaultQueue, true, 3)
-_SPIRV_OP(BuildNDRange, true, 6)
-#undef _SPIRV_OP
-
-class SPIRVPipeInstBase:public SPIRVInstTemplateBase {
-public:
- SPIRVCapVec getRequiredCapability() const override {
- return getVec(CapabilityPipes);
- }
-};
-
-#define _SPIRV_OP(x, ...) \
- typedef SPIRVInstTemplate<SPIRVPipeInstBase, Op##x, __VA_ARGS__> \
- SPIRV##x;
-// CL 2.0 pipe builtins
-_SPIRV_OP(ReadPipe, true, 7)
-_SPIRV_OP(WritePipe, true, 7)
-_SPIRV_OP(ReservedReadPipe, true, 9)
-_SPIRV_OP(ReservedWritePipe, true, 9)
-_SPIRV_OP(ReserveReadPipePackets, true, 7)
-_SPIRV_OP(ReserveWritePipePackets, true, 7)
-_SPIRV_OP(CommitReadPipe, false, 5)
-_SPIRV_OP(CommitWritePipe, false, 5)
-_SPIRV_OP(IsValidReserveId, true, 4)
-_SPIRV_OP(GetNumPipePackets, true, 6)
-_SPIRV_OP(GetMaxPipePackets, true, 6)
-#undef _SPIRV_OP
-
-class SPIRVPipeStorageInstBase :public SPIRVInstTemplateBase {
-public:
- SPIRVCapVec getRequiredCapability() const override {
- return getVec(CapabilityPipeStorage, CapabilityPipes);
- }
-};
-
-#define _SPIRV_OP(x, ...) \
- typedef SPIRVInstTemplate<SPIRVPipeStorageInstBase, Op##x, __VA_ARGS__> \
- SPIRV##x;
-
-_SPIRV_OP(CreatePipeFromPipeStorage, true, 4)
-#undef _SPIRV_OP
-
-class SPIRVGroupInstBase:public SPIRVInstTemplateBase {
-public:
- SPIRVCapVec getRequiredCapability() const override {
- return getVec(CapabilityGroups);
- }
-};
-
-#define _SPIRV_OP(x, ...) \
- typedef SPIRVInstTemplate<SPIRVGroupInstBase, Op##x, __VA_ARGS__> \
- SPIRV##x;
-// Group instructions
-_SPIRV_OP(GroupWaitEvents, false, 4)
-_SPIRV_OP(GroupAll, true, 5)
-_SPIRV_OP(GroupAny, true, 5)
-_SPIRV_OP(GroupBroadcast, true, 6)
-_SPIRV_OP(GroupIAdd, true, 6, false, 1)
-_SPIRV_OP(GroupFAdd, true, 6, false, 1)
-_SPIRV_OP(GroupFMin, true, 6, false, 1)
-_SPIRV_OP(GroupUMin, true, 6, false, 1)
-_SPIRV_OP(GroupSMin, true, 6, false, 1)
-_SPIRV_OP(GroupFMax, true, 6, false, 1)
-_SPIRV_OP(GroupUMax, true, 6, false, 1)
-_SPIRV_OP(GroupSMax, true, 6, false, 1)
-_SPIRV_OP(GroupReserveReadPipePackets, true, 8)
-_SPIRV_OP(GroupReserveWritePipePackets, true, 8)
-_SPIRV_OP(GroupCommitReadPipe, false, 6)
-_SPIRV_OP(GroupCommitWritePipe, false, 6)
-#undef _SPIRV_OP
-
-class SPIRVAtomicInstBase : public SPIRVInstTemplateBase {
-public:
- SPIRVCapVec getRequiredCapability() const override {
- SPIRVCapVec CapVec;
- // Most of atomic instructions do not require any capabilities
- // ... unless they operate on 64-bit integers.
- if (hasType() && getType()->isTypeInt(64)) {
- // In SPIRV 1.2 spec only 2 atomic instructions have no result type:
- // 1. OpAtomicStore - need to check type of the Value operand
- // 2. OpAtomicFlagClear - doesn't require Int64Atomics capability.
- CapVec.push_back(CapabilityInt64Atomics);
- }
- // Per the spec OpAtomicCompareExchangeWeak, OpAtomicFlagTestAndSet and
- // OpAtomicFlagClear instructions require kernel capability. But this
- // capability should be added by setting OpenCL memory model.
- return CapVec;
- }
-
- // Overriding the following method only because of OpAtomicStore.
- // We have to declare Int64Atomics capability if the Value operand is int64.
- void setOpWords(const std::vector<SPIRVWord> &TheOps) override {
- SPIRVInstTemplateBase::setOpWords(TheOps);
- static const unsigned ValueOperandIndex = 3;
- if (getOpCode() == OpAtomicStore &&
- getOperand(ValueOperandIndex)->getType()->isTypeInt(64))
- Module->addCapability(CapabilityInt64Atomics);
- }
-};
-
-#define _SPIRV_OP(x, ...) \
- typedef SPIRVInstTemplate<SPIRVAtomicInstBase, Op##x, __VA_ARGS__> \
- SPIRV##x;
-// Atomic builtins
-_SPIRV_OP(AtomicFlagTestAndSet, true, 6)
-_SPIRV_OP(AtomicFlagClear, false, 4)
-_SPIRV_OP(AtomicLoad, true, 6)
-_SPIRV_OP(AtomicStore, false, 5)
-_SPIRV_OP(AtomicExchange, true, 7)
-_SPIRV_OP(AtomicCompareExchange, true, 9)
-_SPIRV_OP(AtomicCompareExchangeWeak, true, 9)
-_SPIRV_OP(AtomicIIncrement, true, 6)
-_SPIRV_OP(AtomicIDecrement, true, 6)
-_SPIRV_OP(AtomicIAdd, true, 7)
-_SPIRV_OP(AtomicISub, true, 7)
-_SPIRV_OP(AtomicUMin, true, 7)
-_SPIRV_OP(AtomicUMax, true, 7)
-_SPIRV_OP(AtomicSMin, true, 7)
-_SPIRV_OP(AtomicSMax, true, 7)
-_SPIRV_OP(AtomicAnd, true, 7)
-_SPIRV_OP(AtomicOr, true, 7)
-_SPIRV_OP(AtomicXor, true, 7)
-_SPIRV_OP(MemoryBarrier, false, 3)
-#undef _SPIRV_OP
-
-class SPIRVImageInstBase:public SPIRVInstTemplateBase {
-public:
- SPIRVCapVec getRequiredCapability() const override {
- return getVec(CapabilityImageBasic);
- }
-};
-
-#define _SPIRV_OP(x, ...) \
- typedef SPIRVInstTemplate<SPIRVImageInstBase, Op##x, __VA_ARGS__> \
- SPIRV##x;
-// Image instructions
-_SPIRV_OP(SampledImage, true, 5)
-_SPIRV_OP(ImageSampleImplicitLod, true, 5, true)
-_SPIRV_OP(ImageSampleExplicitLod, true, 7, true, 2)
-_SPIRV_OP(ImageRead, true, 5, true, 2)
-_SPIRV_OP(ImageWrite, false, 4, true, 3)
-_SPIRV_OP(ImageQueryFormat, true, 4)
-_SPIRV_OP(ImageQueryOrder, true, 4)
-_SPIRV_OP(ImageQuerySizeLod, true, 5)
-_SPIRV_OP(ImageQuerySize, true, 4)
-_SPIRV_OP(ImageQueryLod, true, 5)
-_SPIRV_OP(ImageQueryLevels, true, 4)
-_SPIRV_OP(ImageQuerySamples, true, 4)
-#undef _SPIRV_OP
-
-#define _SPIRV_OP(x, ...) \
- typedef SPIRVInstTemplate<SPIRVInstTemplateBase, Op##x, __VA_ARGS__> \
- SPIRV##x;
-// Other instructions
-_SPIRV_OP(SpecConstantOp, true, 4, true, 0)
-_SPIRV_OP(GenericPtrMemSemantics, true, 4, false)
-_SPIRV_OP(GenericCastToPtrExplicit, true, 5, false, 1)
-#undef _SPIRV_OP
-
-class SPIRVSubgroupShuffleINTELInstBase:public SPIRVInstTemplateBase {
-protected:
- SPIRVCapVec getRequiredCapability() const override {
- return getVec(CapabilitySubgroupShuffleINTEL);
- }
-};
-
-#define _SPIRV_OP(x, ...) \
- typedef SPIRVInstTemplate<SPIRVSubgroupShuffleINTELInstBase, Op##x, __VA_ARGS__> \
- SPIRV##x;
-// Intel Subgroup Shuffle Instructions
-_SPIRV_OP(SubgroupShuffleINTEL, true, 5)
-_SPIRV_OP(SubgroupShuffleDownINTEL, true, 6)
-_SPIRV_OP(SubgroupShuffleUpINTEL, true, 6)
-_SPIRV_OP(SubgroupShuffleXorINTEL, true, 5)
-#undef _SPIRV_OP
-
-class SPIRVSubgroupBufferBlockIOINTELInstBase:public SPIRVInstTemplateBase {
-protected:
- SPIRVCapVec getRequiredCapability() const override {
- return getVec(CapabilitySubgroupBufferBlockIOINTEL);
- }
-};
-
-#define _SPIRV_OP(x, ...) \
- typedef SPIRVInstTemplate<SPIRVSubgroupBufferBlockIOINTELInstBase, Op##x, __VA_ARGS__> \
- SPIRV##x;
-// Intel Subgroup Buffer Block Read and Write Instructions
-_SPIRV_OP(SubgroupBlockReadINTEL, true, 4)
-_SPIRV_OP(SubgroupBlockWriteINTEL, false, 3)
-#undef _SPIRV_OP
-
-class SPIRVSubgroupImageBlockIOINTELInstBase:public SPIRVInstTemplateBase {
-protected:
- SPIRVCapVec getRequiredCapability() const override {
- return getVec(CapabilitySubgroupImageBlockIOINTEL);
- }
-};
-
-#define _SPIRV_OP(x, ...) \
- typedef SPIRVInstTemplate<SPIRVSubgroupImageBlockIOINTELInstBase, Op##x, __VA_ARGS__> \
- SPIRV##x;
-// Intel Subgroup Image Block Read and Write Instructions
-_SPIRV_OP(SubgroupImageBlockReadINTEL, true, 5)
-_SPIRV_OP(SubgroupImageBlockWriteINTEL, false, 4)
-#undef _SPIRV_OP
-
-
-SPIRVSpecConstantOp *createSpecConstantOpInst(SPIRVInstruction *Inst);
-SPIRVInstruction *createInstFromSpecConstantOp(SPIRVSpecConstantOp *C);
-}
-
-#endif // SPIRVINSTRUCTION_HPP_
+ assert(getType() == getValueType(Op) && + "Inconsistent type"); + assert((resTy->isTypeInt() || resTy->isTypeFloat()) && + "Invalid type for Generic Negate instruction"); + assert((resTy->getBitWidth() == opTy->getBitWidth()) && + "Invalid bitwidth for Generic Negate instruction"); + assert((Type->isTypeVector() ? (Type->getVectorComponentCount() == + getValueType(Op)->getVectorComponentCount()): 1) && + "Invalid vector component Width for Generic Negate instruction"); + } + } +}; + +template<Op OC> +class SPIRVUnaryInst:public SPIRVInstTemplate<SPIRVUnary, OC, true, 4, false> { +}; + +#define _SPIRV_OP(x) typedef SPIRVUnaryInst<Op##x> SPIRV##x; +_SPIRV_OP(ConvertFToU) +_SPIRV_OP(ConvertFToS) +_SPIRV_OP(ConvertSToF) +_SPIRV_OP(ConvertUToF) +_SPIRV_OP(UConvert) +_SPIRV_OP(SConvert) +_SPIRV_OP(FConvert) +_SPIRV_OP(SatConvertSToU) +_SPIRV_OP(SatConvertUToS) +_SPIRV_OP(ConvertPtrToU) +_SPIRV_OP(ConvertUToPtr) +_SPIRV_OP(PtrCastToGeneric) +_SPIRV_OP(GenericCastToPtr) +_SPIRV_OP(Bitcast) +_SPIRV_OP(SNegate) +_SPIRV_OP(FNegate) +_SPIRV_OP(Not) +_SPIRV_OP(LogicalNot) +_SPIRV_OP(IsNan) +_SPIRV_OP(IsInf) +_SPIRV_OP(IsFinite) +_SPIRV_OP(IsNormal) +_SPIRV_OP(SignBitSet) +_SPIRV_OP(Any) +_SPIRV_OP(All) +#undef _SPIRV_OP + +class SPIRVAccessChainBase :public SPIRVInstTemplateBase { +public: + SPIRVValue *getBase() { return this->getValue(this->Ops[0]);} + std::vector<SPIRVValue *> getIndices()const { + std::vector<SPIRVWord> IndexWords(this->Ops.begin() + 1, this->Ops.end()); + return this->getValues(IndexWords); + } + bool isInBounds() { + return OpCode == OpInBoundsAccessChain || + OpCode == OpInBoundsPtrAccessChain; + } + bool hasPtrIndex() { + return OpCode == OpPtrAccessChain || + OpCode == OpInBoundsPtrAccessChain; + } +}; + +template<Op OC, unsigned FixedWC> +class SPIRVAccessChainGeneric + :public SPIRVInstTemplate<SPIRVAccessChainBase, OC, true, FixedWC, true> { +}; + +typedef SPIRVAccessChainGeneric<OpAccessChain, 4> SPIRVAccessChain; +typedef SPIRVAccessChainGeneric<OpInBoundsAccessChain, 4> + SPIRVInBoundsAccessChain; +typedef SPIRVAccessChainGeneric<OpPtrAccessChain, 5> SPIRVPtrAccessChain; +typedef SPIRVAccessChainGeneric<OpInBoundsPtrAccessChain, 5> + SPIRVInBoundsPtrAccessChain; + +template<Op OC, SPIRVWord FixedWordCount> +class SPIRVFunctionCallGeneric: public SPIRVInstruction { +public: + SPIRVFunctionCallGeneric(SPIRVType *TheType, SPIRVId TheId, + const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB) + :SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, TheId, BB), + Args(TheArgs){ + validate(); + assert(BB && "Invalid BB"); + } + SPIRVFunctionCallGeneric(SPIRVType *TheType, SPIRVId TheId, + const std::vector<SPIRVValue *> &TheArgs, SPIRVBasicBlock *BB) + :SPIRVInstruction(TheArgs.size() + FixedWordCount, OC, TheType, TheId, BB) { + Args = getIds(TheArgs); + validate(); + assert(BB && "Invalid BB"); + } + SPIRVFunctionCallGeneric():SPIRVInstruction(OC) {} + const std::vector<SPIRVWord> &getArguments() { + return Args; + } + std::vector<SPIRVValue *> getArgumentValues() { + return getValues(Args); + } + std::vector<SPIRVType *> getArgumentValueTypes()const { + std::vector<SPIRVType *> ArgTypes; + for (auto &I:Args) + ArgTypes.push_back(getValue(I)->getType()); + return ArgTypes; + } + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + Args.resize(TheWordCount - FixedWordCount); + } + void validate()const { + SPIRVInstruction::validate(); + } +protected: + std::vector<SPIRVWord> Args; +}; + +class SPIRVFunctionCall: + public SPIRVFunctionCallGeneric<OpFunctionCall, 4> { +public: + SPIRVFunctionCall(SPIRVId TheId, SPIRVFunction *TheFunction, + const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB); + SPIRVFunctionCall():FunctionId(SPIRVID_INVALID) {} + SPIRVFunction *getFunction()const { + return get<SPIRVFunction>(FunctionId); + } + _SPIRV_DEF_ENCDEC4(Type, Id, FunctionId, Args) + void validate()const; + bool isOperandLiteral(unsigned Index) const { return false;} +protected: + SPIRVId FunctionId; +}; + +class SPIRVExtInst: public SPIRVFunctionCallGeneric<OpExtInst, 5> { +public: + SPIRVExtInst(SPIRVType *TheType, SPIRVId TheId, + SPIRVId TheBuiltinSet, SPIRVWord TheEntryPoint, + const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB) + :SPIRVFunctionCallGeneric(TheType, TheId, TheArgs, BB), + ExtSetId(TheBuiltinSet), + ExtOp(TheEntryPoint) { + setExtSetKindById(); + validate(); + } + SPIRVExtInst(SPIRVType *TheType, SPIRVId TheId, + SPIRVId TheBuiltinSet, SPIRVWord TheEntryPoint, + const std::vector<SPIRVValue *> &TheArgs, SPIRVBasicBlock *BB) + :SPIRVFunctionCallGeneric(TheType, TheId, TheArgs, BB), + ExtSetId(TheBuiltinSet), + ExtOp(TheEntryPoint) { + setExtSetKindById(); + validate(); + } + SPIRVExtInst(SPIRVExtInstSetKind SetKind = SPIRVEIS_Count, + unsigned ExtOC = SPIRVWORD_MAX) + :ExtSetId(SPIRVWORD_MAX), ExtOp(ExtOC), ExtSetKind(SetKind) {} + void setExtSetId(unsigned Set) { ExtSetId = Set;} + void setExtOp(unsigned ExtOC) { ExtOp = ExtOC;} + SPIRVId getExtSetId()const { + return ExtSetId; + } + SPIRVWord getExtOp()const { + return ExtOp; + } + void setExtSetKindById() { + assert(Module && "Invalid module"); + ExtSetKind = Module->getBuiltinSet(ExtSetId); + assert(ExtSetKind == SPIRVEIS_OpenCL && "not supported"); + } + void encode(spv_ostream &O) const { + getEncoder(O) << Type << Id << ExtSetId; + switch(ExtSetKind) { + case SPIRVEIS_OpenCL: + getEncoder(O) << ExtOpOCL; + break; + default: + assert(0 && "not supported"); + getEncoder(O) << ExtOp; + } + getEncoder(O) << Args; + } + void decode(std::istream &I) { + getDecoder(I) >> Type >> Id >> ExtSetId; + setExtSetKindById(); + switch(ExtSetKind) { + case SPIRVEIS_OpenCL: + getDecoder(I) >> ExtOpOCL; + break; + default: + assert(0 && "not supported"); + getDecoder(I) >> ExtOp; + } + getDecoder(I) >> Args; + } + void validate()const { + SPIRVFunctionCallGeneric::validate(); + validateBuiltin(ExtSetId, ExtOp); + } + bool isOperandLiteral(unsigned Index) const { + assert(ExtSetKind == SPIRVEIS_OpenCL && + "Unsupported extended instruction set"); + auto EOC = static_cast<OCLExtOpKind>(ExtOp); + switch(EOC) { + default: + return false; + case OpenCLLIB::Vloadn: + case OpenCLLIB::Vload_halfn: + case OpenCLLIB::Vloada_halfn: + return Index == 2; + case OpenCLLIB::Vstore_half_r: + case OpenCLLIB::Vstore_halfn_r: + case OpenCLLIB::Vstorea_halfn_r: + return Index == 3; + } + } +protected: + SPIRVId ExtSetId; + union { + SPIRVWord ExtOp; + OCLExtOpKind ExtOpOCL; + }; + SPIRVExtInstSetKind ExtSetKind; +}; + +class SPIRVCompositeConstruct : public SPIRVInstruction { +public: + const static Op OC = OpCompositeConstruct; + const static SPIRVWord FixedWordCount = 3; + // Complete constructor + SPIRVCompositeConstruct(SPIRVType *TheType, SPIRVId TheId, + const std::vector<SPIRVId>& TheConstituents, SPIRVBasicBlock *TheBB) : + SPIRVInstruction(TheConstituents.size() + FixedWordCount, OC, + TheType, TheId, TheBB), Constituents(TheConstituents) { + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVCompositeConstruct():SPIRVInstruction(OC) {} + + const std::vector<SPIRVValue*> getConstituents() const { + return getValues(Constituents); + } +protected: + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + Constituents.resize(TheWordCount - FixedWordCount); + } + _SPIRV_DEF_ENCDEC3(Type, Id, Constituents) + void validate() const { + SPIRVInstruction::validate(); + switch (getValueType(this->getId())->getOpCode()) { + case OpTypeVector: + assert(getConstituents().size() > 1 && + "There must be at least two Constituent operands in vector"); + case OpTypeArray: + case OpTypeStruct: + break; + default: + assert("Invalid type"); + } + } + std::vector<SPIRVId> Constituents; +}; + +class SPIRVCompositeExtract:public SPIRVInstruction { +public: + const static Op OC = OpCompositeExtract; + // Complete constructor + SPIRVCompositeExtract(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheComposite, + const std::vector<SPIRVWord>& TheIndices, SPIRVBasicBlock *TheBB): + SPIRVInstruction(TheIndices.size() + 4, OC, TheType, TheId, TheBB), + Composite(TheComposite->getId()), Indices(TheIndices){ + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVCompositeExtract():SPIRVInstruction(OC), Composite(SPIRVID_INVALID){} + + SPIRVValue *getComposite() { return getValue(Composite);} + const std::vector<SPIRVWord>& getIndices()const { return Indices;} +protected: + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + Indices.resize(TheWordCount - 4); + } + _SPIRV_DEF_ENCDEC4(Type, Id, Composite, Indices) + // ToDo: validate the result type is consistent with the base type and indices + // need to trace through the base type for struct types + void validate()const { + SPIRVInstruction::validate(); + assert(getValueType(Composite)->isTypeArray() || + getValueType(Composite)->isTypeStruct() || + getValueType(Composite)->isTypeVector()); + } + SPIRVId Composite; + std::vector<SPIRVWord> Indices; +}; + +class SPIRVCompositeInsert:public SPIRVInstruction { +public: + const static Op OC = OpCompositeInsert; + const static SPIRVWord FixedWordCount = 5; + // Complete constructor + SPIRVCompositeInsert(SPIRVId TheId, SPIRVValue *TheObject, + SPIRVValue *TheComposite, const std::vector<SPIRVWord>& TheIndices, + SPIRVBasicBlock *TheBB): + SPIRVInstruction(TheIndices.size() + FixedWordCount, OC, + TheComposite->getType(), TheId, TheBB), + Object(TheObject->getId()), Composite(TheComposite->getId()), + Indices(TheIndices){ + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVCompositeInsert():SPIRVInstruction(OC), Object(SPIRVID_INVALID), + Composite(SPIRVID_INVALID){} + + SPIRVValue *getObject() { return getValue(Object);} + SPIRVValue *getComposite() { return getValue(Composite);} + const std::vector<SPIRVWord>& getIndices()const { return Indices;} +protected: + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + Indices.resize(TheWordCount - FixedWordCount); + } + _SPIRV_DEF_ENCDEC5(Type, Id, Object, Composite, Indices) + // ToDo: validate the object type is consistent with the base type and indices + // need to trace through the base type for struct types + void validate()const { + SPIRVInstruction::validate(); + assert(OpCode == OC); + assert(WordCount == Indices.size() + FixedWordCount); + assert(getValueType(Composite)->isTypeArray() || + getValueType(Composite)->isTypeStruct() || + getValueType(Composite)->isTypeVector()); + assert(Type == getValueType(Composite)); + } + SPIRVId Object; + SPIRVId Composite; + std::vector<SPIRVWord> Indices; +}; + +class SPIRVCopyObject :public SPIRVInstruction { +public: + const static Op OC = OpCopyObject; + + // Complete constructor + SPIRVCopyObject(SPIRVType *TheType, SPIRVId TheId, SPIRVValue *TheOperand, + SPIRVBasicBlock *TheBB) : + SPIRVInstruction(4, OC, TheType, TheId, TheBB), + Operand(TheOperand->getId()) { + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVCopyObject() :SPIRVInstruction(OC), Operand(SPIRVID_INVALID) {} + + SPIRVValue *getOperand() { return getValue(Operand); } + +protected: + _SPIRV_DEF_ENCDEC3(Type, Id, Operand) + + void validate()const { + SPIRVInstruction::validate(); + } + SPIRVId Operand; +}; + + +class SPIRVCopyMemory :public SPIRVInstruction, public SPIRVMemoryAccess { +public: + const static Op OC = OpCopyMemory; + const static SPIRVWord FixedWords = 3; + // Complete constructor + SPIRVCopyMemory(SPIRVValue *TheTarget, SPIRVValue *TheSource, + const std::vector<SPIRVWord> &TheMemoryAccess, + SPIRVBasicBlock *TheBB) : + SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OC, TheBB), + SPIRVMemoryAccess(TheMemoryAccess), + MemoryAccess(TheMemoryAccess), + Target(TheTarget->getId()), + Source(TheSource->getId()) { + validate(); + assert(TheBB && "Invalid BB"); + } + + // Incomplete constructor + SPIRVCopyMemory() :SPIRVInstruction(OC), SPIRVMemoryAccess(), + Target(SPIRVID_INVALID), + Source(SPIRVID_INVALID) { + setHasNoId(); + setHasNoType(); + } + + SPIRVValue *getSource() { return getValue(Source); } + SPIRVValue *getTarget() { return getValue(Target); } + +protected: + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + MemoryAccess.resize(TheWordCount - FixedWords); + } + + void encode(spv_ostream &O) const { + getEncoder(O) << Target << Source << MemoryAccess; + } + + void decode(std::istream &I) { + getDecoder(I) >> Target >> Source >> MemoryAccess; + MemoryAccessUpdate(MemoryAccess); + } + + void validate()const { + assert((getValueType(Id) == getValueType(Source)) && "Inconsistent type"); + assert(getValueType(Id)->isTypePointer() && "Invalid type"); + assert(!(getValueType(Id)->getPointerElementType()->isTypeVoid()) && + "Invalid type"); + SPIRVInstruction::validate(); + } + + std::vector<SPIRVWord> MemoryAccess; + SPIRVId Target; + SPIRVId Source; +}; + +class SPIRVCopyMemorySized :public SPIRVInstruction, public SPIRVMemoryAccess { +public: + const static Op OC = OpCopyMemorySized; + const static SPIRVWord FixedWords = 4; + // Complete constructor + SPIRVCopyMemorySized(SPIRVValue *TheTarget, SPIRVValue *TheSource, + SPIRVValue *TheSize, const std::vector<SPIRVWord> &TheMemoryAccess, + SPIRVBasicBlock *TheBB) : + SPIRVInstruction(FixedWords + TheMemoryAccess.size(), OC, TheBB), + SPIRVMemoryAccess(TheMemoryAccess), + MemoryAccess(TheMemoryAccess), + Target(TheTarget->getId()), + Source(TheSource->getId()), + Size(TheSize->getId()) { + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVCopyMemorySized() :SPIRVInstruction(OC), SPIRVMemoryAccess(), + Target(SPIRVID_INVALID), Source(SPIRVID_INVALID), Size(0) { + setHasNoId(); + setHasNoType(); + } + + SPIRVValue *getSource() { return getValue(Source); } + SPIRVValue *getTarget() { return getValue(Target); } + SPIRVValue *getSize() { return getValue(Size); } + +protected: + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + MemoryAccess.resize(TheWordCount - FixedWords); + } + + void encode(spv_ostream &O) const { + getEncoder(O) << Target << Source << Size << MemoryAccess; + } + + void decode(std::istream &I) { + getDecoder(I) >> Target >> Source >> Size >> MemoryAccess; + MemoryAccessUpdate(MemoryAccess); + } + + void validate()const { + SPIRVInstruction::validate(); + } + + std::vector<SPIRVWord> MemoryAccess; + SPIRVId Target; + SPIRVId Source; + SPIRVId Size; +}; + +class SPIRVVectorExtractDynamic:public SPIRVInstruction { +public: + const static Op OC = OpVectorExtractDynamic; + // Complete constructor + SPIRVVectorExtractDynamic(SPIRVId TheId, SPIRVValue *TheVector, + SPIRVValue* TheIndex, SPIRVBasicBlock *TheBB) + :SPIRVInstruction(5, OC, TheVector->getType()->getVectorComponentType(), + TheId, TheBB), VectorId(TheVector->getId()), + IndexId(TheIndex->getId()){ + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVVectorExtractDynamic():SPIRVInstruction(OC), VectorId(SPIRVID_INVALID), + IndexId(SPIRVID_INVALID){} + + SPIRVValue *getVector() { return getValue(VectorId);} + SPIRVValue *getIndex()const { return getValue(IndexId);} +protected: + _SPIRV_DEF_ENCDEC4(Type, Id, VectorId, IndexId) + void validate()const { + SPIRVInstruction::validate(); + if (getValue(VectorId)->isForward()) + return; + assert(getValueType(VectorId)->isTypeVector()); + } + SPIRVId VectorId; + SPIRVId IndexId; +}; + +class SPIRVVectorInsertDynamic :public SPIRVInstruction { +public: + const static Op OC = OpVectorInsertDynamic; + // Complete constructor + SPIRVVectorInsertDynamic(SPIRVId TheId, SPIRVValue *TheVector, + SPIRVValue* TheComponent, SPIRVValue* TheIndex, SPIRVBasicBlock *TheBB) + :SPIRVInstruction(6, OC, TheVector->getType()->getVectorComponentType(), + TheId, TheBB), VectorId(TheVector->getId()), + IndexId(TheIndex->getId()), ComponentId(TheComponent->getId()){ + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVVectorInsertDynamic() :SPIRVInstruction(OC), VectorId(SPIRVID_INVALID), + IndexId(SPIRVID_INVALID), ComponentId(SPIRVID_INVALID){} + + SPIRVValue *getVector() { return getValue(VectorId); } + SPIRVValue *getIndex()const { return getValue(IndexId); } + SPIRVValue *getComponent() { return getValue(ComponentId); } +protected: + _SPIRV_DEF_ENCDEC5(Type, Id, VectorId, ComponentId, IndexId) + void validate()const { + SPIRVInstruction::validate(); + if (getValue(VectorId)->isForward()) + return; + assert(getValueType(VectorId)->isTypeVector()); + } + SPIRVId VectorId; + SPIRVId IndexId; + SPIRVId ComponentId; +}; + +class SPIRVVectorShuffle:public SPIRVInstruction { +public: + const static Op OC = OpVectorShuffle; + const static SPIRVWord FixedWordCount = 5; + // Complete constructor + SPIRVVectorShuffle(SPIRVId TheId, SPIRVType *TheType, SPIRVValue *TheVector1, + SPIRVValue *TheVector2, const std::vector<SPIRVWord>& TheComponents, + SPIRVBasicBlock *TheBB): + SPIRVInstruction(TheComponents.size() + FixedWordCount, OC, TheType, + TheId, TheBB), + Vector1(TheVector1->getId()), Vector2(TheVector2->getId()), + Components(TheComponents){ + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVVectorShuffle():SPIRVInstruction(OC), Vector1(SPIRVID_INVALID), + Vector2(SPIRVID_INVALID){} + + SPIRVValue *getVector1() { return getValue(Vector1);} + SPIRVValue *getVector2() { return getValue(Vector2);} + const std::vector<SPIRVWord>& getComponents()const { return Components;} +protected: + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + Components.resize(TheWordCount - FixedWordCount); + } + _SPIRV_DEF_ENCDEC5(Type, Id, Vector1, Vector2, Components) + void validate()const { + SPIRVInstruction::validate(); + assert(OpCode == OC); + assert(WordCount == Components.size() + FixedWordCount); + assert(Type->isTypeVector()); + assert(Type->getVectorComponentType() == + getValueType(Vector1)->getVectorComponentType()); + if (getValue(Vector1)->isForward() || + getValue(Vector2)->isForward()) + return; + assert(getValueType(Vector1) == getValueType(Vector2)); + assert(Components.size() == Type->getVectorComponentCount()); + assert(Components.size() > 1); + } + SPIRVId Vector1; + SPIRVId Vector2; + std::vector<SPIRVWord> Components; +}; + +class SPIRVControlBarrier:public SPIRVInstruction { +public: + static const Op OC = OpControlBarrier; + // Complete constructor + SPIRVControlBarrier(SPIRVValue *TheScope, + SPIRVValue *TheMemScope, SPIRVValue *TheMemSema, + SPIRVBasicBlock *TheBB) + :SPIRVInstruction(4, OC, TheBB), ExecScope(TheScope->getId()), + MemScope(TheMemScope->getId()), MemSema(TheMemSema->getId()){ + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVControlBarrier():SPIRVInstruction(OC), ExecScope(ScopeInvocation) { + setHasNoId(); + setHasNoType(); + } + void setWordCount(SPIRVWord TheWordCount) { + SPIRVEntry::setWordCount(TheWordCount); + } + SPIRVValue *getExecScope() const { return getValue(ExecScope); } + SPIRVValue *getMemScope() const { return getValue(MemScope); } + SPIRVValue *getMemSemantic() const { return getValue(MemSema); } + std::vector<SPIRVValue *> getOperands() { + std::vector<SPIRVId> Operands; + Operands.push_back(ExecScope); + Operands.push_back(MemScope); + Operands.push_back(MemSema); + return getValues(Operands); + } +protected: + _SPIRV_DEF_ENCDEC3(ExecScope, MemScope, MemSema) + void validate()const { + assert(OpCode == OC); + assert(WordCount == 4); + SPIRVInstruction::validate(); + } + SPIRVId ExecScope; + SPIRVId MemScope; + SPIRVId MemSema; +}; + +template<Op OC> +class SPIRVLifetime : public SPIRVInstruction { +public: + // Complete constructor + SPIRVLifetime(SPIRVId TheObject, SPIRVWord TheSize, + SPIRVBasicBlock *TheBB) : + SPIRVInstruction(3, OC, TheBB), Object(TheObject), Size(TheSize) { + validate(); + assert(TheBB && "Invalid BB"); + }; + // Incomplete constructor + SPIRVLifetime() :SPIRVInstruction(OC), Object(SPIRVID_INVALID), + Size(SPIRVWORD_MAX) { + setHasNoId(); + setHasNoType(); + } + SPIRVCapVec getRequiredCapability() const override { + return getVec(CapabilityKernel); + } + SPIRVValue *getObject() { return getValue(Object); }; + SPIRVWord getSize() { return Size; }; +protected: + void validate() const { + auto Obj = static_cast<SPIRVVariable*>(getValue(Object)); + assert(Obj->getStorageClass() == StorageClassFunction && + "Invalid storage class"); + assert(Obj->getType()->isTypePointer() && + "Objects type must be a pointer"); + if (!Obj->getType()->getPointerElementType()->isTypeVoid() || + !Module->hasCapability(CapabilityAddresses)) + assert(Size == 0 && "Size must be 0"); + } + _SPIRV_DEF_ENCDEC2(Object, Size) + SPIRVId Object; + SPIRVWord Size; +}; + +typedef SPIRVLifetime<OpLifetimeStart> SPIRVLifetimeStart; +typedef SPIRVLifetime<OpLifetimeStop> SPIRVLifetimeStop; + +class SPIRVGroupAsyncCopy:public SPIRVInstruction { +public: + static const Op OC = OpGroupAsyncCopy; + static const SPIRVWord WC = 9; + // Complete constructor + SPIRVGroupAsyncCopy(SPIRVValue *TheScope, SPIRVId TheId, + SPIRVValue *TheDest, SPIRVValue *TheSrc, SPIRVValue *TheNumElems, + SPIRVValue *TheStride, SPIRVValue *TheEvent, SPIRVBasicBlock *TheBB) + :SPIRVInstruction(WC, OC, TheEvent->getType(), TheId, TheBB), + ExecScope(TheScope->getId()), Destination(TheDest->getId()), + Source(TheSrc->getId()), NumElements(TheNumElems->getId()), + Stride(TheStride->getId()), Event(TheEvent->getId()){ + validate(); + assert(TheBB && "Invalid BB"); + } + // Incomplete constructor + SPIRVGroupAsyncCopy():SPIRVInstruction(OC), ExecScope(SPIRVID_INVALID), + Destination(SPIRVID_INVALID), Source(SPIRVID_INVALID), + NumElements(SPIRVID_INVALID), Stride(SPIRVID_INVALID), + Event(SPIRVID_INVALID){ + } + SPIRVValue *getExecScope() const { return getValue(ExecScope); } + SPIRVValue *getDestination()const { return getValue(Destination);} + SPIRVValue *getSource()const { return getValue(Source);} + SPIRVValue *getNumElements()const { return getValue(NumElements);} + SPIRVValue *getStride()const { return getValue(Stride);} + SPIRVValue *getEvent()const { return getValue(Event);} + std::vector<SPIRVValue *> getOperands() { + std::vector<SPIRVId> Operands; + Operands.push_back(Destination); + Operands.push_back(Source); + Operands.push_back(NumElements); + Operands.push_back(Stride); + Operands.push_back(Event); + return getValues(Operands); + } + +protected: + _SPIRV_DEF_ENCDEC8(Type, Id, ExecScope, Destination, Source, NumElements, + Stride, Event) + void validate()const { + assert(OpCode == OC); + assert(WordCount == WC); + SPIRVInstruction::validate(); + } + SPIRVId ExecScope; + SPIRVId Destination; + SPIRVId Source; + SPIRVId NumElements; + SPIRVId Stride; + SPIRVId Event; +}; + +enum SPIRVOpKind { + SPIRVOPK_Id, + SPIRVOPK_Literal, + SPIRVOPK_Count +}; + +class SPIRVDevEnqInstBase:public SPIRVInstTemplateBase { +public: + SPIRVCapVec getRequiredCapability() const override { + return getVec(CapabilityDeviceEnqueue); + } +}; + +#define _SPIRV_OP(x, ...) \ + typedef SPIRVInstTemplate<SPIRVDevEnqInstBase, Op##x, __VA_ARGS__> \ + SPIRV##x; +// CL 2.0 enqueue kernel builtins +_SPIRV_OP(EnqueueMarker, true, 7) +_SPIRV_OP(EnqueueKernel, true, 13, true) +_SPIRV_OP(GetKernelNDrangeSubGroupCount, true, 8) +_SPIRV_OP(GetKernelNDrangeMaxSubGroupSize, true, 8) +_SPIRV_OP(GetKernelWorkGroupSize, true, 7) +_SPIRV_OP(GetKernelPreferredWorkGroupSizeMultiple, true, 7) +_SPIRV_OP(RetainEvent, false, 2) +_SPIRV_OP(ReleaseEvent, false, 2) +_SPIRV_OP(CreateUserEvent, true, 3) +_SPIRV_OP(IsValidEvent, true, 4) +_SPIRV_OP(SetUserEventStatus, false, 3) +_SPIRV_OP(CaptureEventProfilingInfo, false, 4) +_SPIRV_OP(GetDefaultQueue, true, 3) +_SPIRV_OP(BuildNDRange, true, 6) +#undef _SPIRV_OP + +class SPIRVPipeInstBase:public SPIRVInstTemplateBase { +public: + SPIRVCapVec getRequiredCapability() const override { + return getVec(CapabilityPipes); + } +}; + +#define _SPIRV_OP(x, ...) \ + typedef SPIRVInstTemplate<SPIRVPipeInstBase, Op##x, __VA_ARGS__> \ + SPIRV##x; +// CL 2.0 pipe builtins +_SPIRV_OP(ReadPipe, true, 7) +_SPIRV_OP(WritePipe, true, 7) +_SPIRV_OP(ReservedReadPipe, true, 9) +_SPIRV_OP(ReservedWritePipe, true, 9) +_SPIRV_OP(ReserveReadPipePackets, true, 7) +_SPIRV_OP(ReserveWritePipePackets, true, 7) +_SPIRV_OP(CommitReadPipe, false, 5) +_SPIRV_OP(CommitWritePipe, false, 5) +_SPIRV_OP(IsValidReserveId, true, 4) +_SPIRV_OP(GetNumPipePackets, true, 6) +_SPIRV_OP(GetMaxPipePackets, true, 6) +#undef _SPIRV_OP + +class SPIRVPipeStorageInstBase :public SPIRVInstTemplateBase { +public: + SPIRVCapVec getRequiredCapability() const override { + return getVec(CapabilityPipeStorage, CapabilityPipes); + } +}; + +#define _SPIRV_OP(x, ...) \ + typedef SPIRVInstTemplate<SPIRVPipeStorageInstBase, Op##x, __VA_ARGS__> \ + SPIRV##x; + +_SPIRV_OP(CreatePipeFromPipeStorage, true, 4) +#undef _SPIRV_OP + +class SPIRVGroupInstBase:public SPIRVInstTemplateBase { +public: + SPIRVCapVec getRequiredCapability() const override { + return getVec(CapabilityGroups); + } +}; + +#define _SPIRV_OP(x, ...) \ + typedef SPIRVInstTemplate<SPIRVGroupInstBase, Op##x, __VA_ARGS__> \ + SPIRV##x; +// Group instructions +_SPIRV_OP(GroupWaitEvents, false, 4) +_SPIRV_OP(GroupAll, true, 5) +_SPIRV_OP(GroupAny, true, 5) +_SPIRV_OP(GroupBroadcast, true, 6) +_SPIRV_OP(GroupIAdd, true, 6, false, 1) +_SPIRV_OP(GroupFAdd, true, 6, false, 1) +_SPIRV_OP(GroupFMin, true, 6, false, 1) +_SPIRV_OP(GroupUMin, true, 6, false, 1) +_SPIRV_OP(GroupSMin, true, 6, false, 1) +_SPIRV_OP(GroupFMax, true, 6, false, 1) +_SPIRV_OP(GroupUMax, true, 6, false, 1) +_SPIRV_OP(GroupSMax, true, 6, false, 1) +_SPIRV_OP(GroupReserveReadPipePackets, true, 8) +_SPIRV_OP(GroupReserveWritePipePackets, true, 8) +_SPIRV_OP(GroupCommitReadPipe, false, 6) +_SPIRV_OP(GroupCommitWritePipe, false, 6) +#undef _SPIRV_OP + +class SPIRVAtomicInstBase : public SPIRVInstTemplateBase { +public: + SPIRVCapVec getRequiredCapability() const override { + SPIRVCapVec CapVec; + // Most of atomic instructions do not require any capabilities + // ... unless they operate on 64-bit integers. + if (hasType() && getType()->isTypeInt(64)) { + // In SPIRV 1.2 spec only 2 atomic instructions have no result type: + // 1. OpAtomicStore - need to check type of the Value operand + // 2. OpAtomicFlagClear - doesn't require Int64Atomics capability. + CapVec.push_back(CapabilityInt64Atomics); + } + // Per the spec OpAtomicCompareExchangeWeak, OpAtomicFlagTestAndSet and + // OpAtomicFlagClear instructions require kernel capability. But this + // capability should be added by setting OpenCL memory model. + return CapVec; + } + + // Overriding the following method only because of OpAtomicStore. + // We have to declare Int64Atomics capability if the Value operand is int64. + void setOpWords(const std::vector<SPIRVWord> &TheOps) override { + SPIRVInstTemplateBase::setOpWords(TheOps); + static const unsigned ValueOperandIndex = 3; + if (getOpCode() == OpAtomicStore && + getOperand(ValueOperandIndex)->getType()->isTypeInt(64)) + Module->addCapability(CapabilityInt64Atomics); + } +}; + +#define _SPIRV_OP(x, ...) \ + typedef SPIRVInstTemplate<SPIRVAtomicInstBase, Op##x, __VA_ARGS__> \ + SPIRV##x; +// Atomic builtins +_SPIRV_OP(AtomicFlagTestAndSet, true, 6) +_SPIRV_OP(AtomicFlagClear, false, 4) +_SPIRV_OP(AtomicLoad, true, 6) +_SPIRV_OP(AtomicStore, false, 5) +_SPIRV_OP(AtomicExchange, true, 7) +_SPIRV_OP(AtomicCompareExchange, true, 9) +_SPIRV_OP(AtomicCompareExchangeWeak, true, 9) +_SPIRV_OP(AtomicIIncrement, true, 6) +_SPIRV_OP(AtomicIDecrement, true, 6) +_SPIRV_OP(AtomicIAdd, true, 7) +_SPIRV_OP(AtomicISub, true, 7) +_SPIRV_OP(AtomicUMin, true, 7) +_SPIRV_OP(AtomicUMax, true, 7) +_SPIRV_OP(AtomicSMin, true, 7) +_SPIRV_OP(AtomicSMax, true, 7) +_SPIRV_OP(AtomicAnd, true, 7) +_SPIRV_OP(AtomicOr, true, 7) +_SPIRV_OP(AtomicXor, true, 7) +_SPIRV_OP(MemoryBarrier, false, 3) +#undef _SPIRV_OP + +class SPIRVImageInstBase:public SPIRVInstTemplateBase { +public: + SPIRVCapVec getRequiredCapability() const override { + return getVec(CapabilityImageBasic); + } +}; + +#define _SPIRV_OP(x, ...) \ + typedef SPIRVInstTemplate<SPIRVImageInstBase, Op##x, __VA_ARGS__> \ + SPIRV##x; +// Image instructions +_SPIRV_OP(SampledImage, true, 5) +_SPIRV_OP(ImageSampleImplicitLod, true, 5, true) +_SPIRV_OP(ImageSampleExplicitLod, true, 7, true, 2) +_SPIRV_OP(ImageRead, true, 5, true, 2) +_SPIRV_OP(ImageWrite, false, 4, true, 3) +_SPIRV_OP(ImageQueryFormat, true, 4) +_SPIRV_OP(ImageQueryOrder, true, 4) +_SPIRV_OP(ImageQuerySizeLod, true, 5) +_SPIRV_OP(ImageQuerySize, true, 4) +_SPIRV_OP(ImageQueryLod, true, 5) +_SPIRV_OP(ImageQueryLevels, true, 4) +_SPIRV_OP(ImageQuerySamples, true, 4) +#undef _SPIRV_OP + +#define _SPIRV_OP(x, ...) \ + typedef SPIRVInstTemplate<SPIRVInstTemplateBase, Op##x, __VA_ARGS__> \ + SPIRV##x; +// Other instructions +_SPIRV_OP(SpecConstantOp, true, 4, true, 0) +_SPIRV_OP(GenericPtrMemSemantics, true, 4, false) +_SPIRV_OP(GenericCastToPtrExplicit, true, 5, false, 1) +#undef _SPIRV_OP + +class SPIRVSubgroupShuffleINTELInstBase:public SPIRVInstTemplateBase { +protected: + SPIRVCapVec getRequiredCapability() const override { + return getVec(CapabilitySubgroupShuffleINTEL); + } +}; + +#define _SPIRV_OP(x, ...) \ + typedef SPIRVInstTemplate<SPIRVSubgroupShuffleINTELInstBase, Op##x, __VA_ARGS__> \ + SPIRV##x; +// Intel Subgroup Shuffle Instructions +_SPIRV_OP(SubgroupShuffleINTEL, true, 5) +_SPIRV_OP(SubgroupShuffleDownINTEL, true, 6) +_SPIRV_OP(SubgroupShuffleUpINTEL, true, 6) +_SPIRV_OP(SubgroupShuffleXorINTEL, true, 5) +#undef _SPIRV_OP + +class SPIRVSubgroupBufferBlockIOINTELInstBase:public SPIRVInstTemplateBase { +protected: + SPIRVCapVec getRequiredCapability() const override { + return getVec(CapabilitySubgroupBufferBlockIOINTEL); + } +}; + +#define _SPIRV_OP(x, ...) \ + typedef SPIRVInstTemplate<SPIRVSubgroupBufferBlockIOINTELInstBase, Op##x, __VA_ARGS__> \ + SPIRV##x; +// Intel Subgroup Buffer Block Read and Write Instructions +_SPIRV_OP(SubgroupBlockReadINTEL, true, 4) +_SPIRV_OP(SubgroupBlockWriteINTEL, false, 3) +#undef _SPIRV_OP + +class SPIRVSubgroupImageBlockIOINTELInstBase:public SPIRVInstTemplateBase { +protected: + SPIRVCapVec getRequiredCapability() const override { + return getVec(CapabilitySubgroupImageBlockIOINTEL); + } +}; + +#define _SPIRV_OP(x, ...) \ + typedef SPIRVInstTemplate<SPIRVSubgroupImageBlockIOINTELInstBase, Op##x, __VA_ARGS__> \ + SPIRV##x; +// Intel Subgroup Image Block Read and Write Instructions +_SPIRV_OP(SubgroupImageBlockReadINTEL, true, 5) +_SPIRV_OP(SubgroupImageBlockWriteINTEL, false, 4) +#undef _SPIRV_OP + + +SPIRVSpecConstantOp *createSpecConstantOpInst(SPIRVInstruction *Inst); +SPIRVInstruction *createInstFromSpecConstantOp(SPIRVSpecConstantOp *C); +} + +#endif // SPIRVINSTRUCTION_HPP_ diff --git a/lib/SPIRV/libSPIRV/SPIRVModule.cpp b/lib/SPIRV/libSPIRV/SPIRVModule.cpp index 33dfeb4..7e3db72 100644 --- a/lib/SPIRV/libSPIRV/SPIRVModule.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVModule.cpp @@ -1,1673 +1,1673 @@ -//===- SPIRVModule.cpp - Class to represent SPIR-V module --------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file implements Module class for SPIR-V.
-///
-//===----------------------------------------------------------------------===//
-
-#include "SPIRVModule.h"
-#include "SPIRVDebug.h"
-#include "SPIRVEntry.h"
-#include "SPIRVType.h"
-#include "SPIRVValue.h"
-#include "SPIRVExtInst.h"
-#include "SPIRVFunction.h"
-#include "SPIRVInstruction.h"
-#include "SPIRVStream.h"
-
-#include <set>
-#include <unordered_map>
-#include <unordered_set>
-
-namespace SPIRV{
-
-SPIRVModule::SPIRVModule():AutoAddCapability(true), ValidateCapability(false)
-{}
-
-SPIRVModule::~SPIRVModule()
-{}
-
-class SPIRVModuleImpl : public SPIRVModule {
-public:
- SPIRVModuleImpl():SPIRVModule(), NextId(1), BoolType(NULL),
- SPIRVVersion(SPIRV_1_0),
- GeneratorId(SPIRVGEN_KhronosLLVMSPIRVTranslator),
- GeneratorVer(0),
- InstSchema(SPIRVISCH_Default),
- SrcLang(SourceLanguageOpenCL_C),
- SrcLangVer(102000) {
- AddrModel = sizeof(size_t) == 32 ? AddressingModelPhysical32
- : AddressingModelPhysical64;
- // OpenCL memory model requires Kernel capability
- setMemoryModel(MemoryModelOpenCL);
- }
- virtual ~SPIRVModuleImpl();
-
- // Object query functions
- bool exist(SPIRVId) const;
- bool exist(SPIRVId, SPIRVEntry **) const;
- SPIRVId getId(SPIRVId Id = SPIRVID_INVALID, unsigned Increment = 1);
- virtual SPIRVEntry *getEntry(SPIRVId Id) const;
- bool hasDebugInfo() const { return !StringVec.empty();}
-
- // Error handling functions
- SPIRVErrorLog &getErrorLog() { return ErrLog;}
- SPIRVErrorCode getError(std::string &ErrMsg) { return ErrLog.getError(ErrMsg);}
-
- // Module query functions
- SPIRVAddressingModelKind getAddressingModel() { return AddrModel;}
- SPIRVExtInstSetKind getBuiltinSet(SPIRVId SetId) const;
- const SPIRVCapMap &getCapability() const { return CapMap; }
- bool hasCapability(SPIRVCapabilityKind Cap) const {
- return CapMap.find(Cap) != CapMap.end();
- }
- std::set<std::string> &getExtension() { return SPIRVExt;}
- SPIRVFunction *getFunction(unsigned I) const { return FuncVec[I];}
- SPIRVVariable *getVariable(unsigned I) const { return VariableVec[I];}
- virtual SPIRVValue *getValue(SPIRVId TheId) const;
- virtual std::vector<SPIRVValue *> getValues(const std::vector<SPIRVId>&)const;
- virtual std::vector<SPIRVId> getIds(const std::vector<SPIRVEntry *>&)const;
- virtual std::vector<SPIRVId> getIds(const std::vector<SPIRVValue *>&)const;
- virtual SPIRVType *getValueType(SPIRVId TheId)const;
- virtual std::vector<SPIRVType *> getValueTypes(const std::vector<SPIRVId>&)
- const;
- SPIRVMemoryModelKind getMemoryModel() const { return MemoryModel;}
- virtual SPIRVConstant* getLiteralAsConstant(unsigned Literal);
- unsigned getNumEntryPoints(SPIRVExecutionModelKind EM) const {
- auto Loc = EntryPointVec.find(EM);
- if (Loc == EntryPointVec.end())
- return 0;
- return Loc->second.size();
- }
- SPIRVFunction *getEntryPoint(SPIRVExecutionModelKind EM, unsigned I) const {
- auto Loc = EntryPointVec.find(EM);
- if (Loc == EntryPointVec.end())
- return nullptr;
- assert(I < Loc->second.size());
- return get<SPIRVFunction>(Loc->second[I]);
- }
- unsigned getNumFunctions() const { return FuncVec.size();}
- unsigned getNumVariables() const { return VariableVec.size();}
- SourceLanguage getSourceLanguage(SPIRVWord * Ver = nullptr) const {
- if (Ver)
- *Ver = SrcLangVer;
- return SrcLang;
- }
- std::set<std::string> &getSourceExtension() { return SrcExtension;}
- bool isEntryPoint(SPIRVExecutionModelKind, SPIRVId EP) const;
- unsigned short getGeneratorId() const { return GeneratorId; }
- unsigned short getGeneratorVer() const { return GeneratorVer; }
- SPIRVWord getSPIRVVersion() const { return SPIRVVersion; }
-
- // Module changing functions
- bool importBuiltinSet(const std::string &, SPIRVId *);
- bool importBuiltinSetWithId(const std::string &, SPIRVId);
- void optimizeDecorates();
- void setAddressingModel(SPIRVAddressingModelKind AM) { AddrModel = AM;}
- void setAlignment(SPIRVValue *, SPIRVWord);
- void setMemoryModel(SPIRVMemoryModelKind MM) {
- MemoryModel = MM;
- if (MemoryModel == spv::MemoryModelOpenCL)
- addCapability(CapabilityKernel);
- }
- void setName(SPIRVEntry *E, const std::string &Name);
- void setSourceLanguage(SourceLanguage Lang, SPIRVWord Ver) {
- SrcLang = Lang;
- SrcLangVer = Ver;
- }
- void setGeneratorId(unsigned short Id) { GeneratorId = Id; }
- void setGeneratorVer(unsigned short Ver) { GeneratorVer = Ver; }
- void resolveUnknownStructFields();
-
- void setSPIRVVersion(SPIRVWord Ver) override { SPIRVVersion = Ver; }
-
- // Object creation functions
- template<class T> void addTo(std::vector<T *> &V, SPIRVEntry *E);
- virtual SPIRVEntry *addEntry(SPIRVEntry *E);
- virtual SPIRVBasicBlock *addBasicBlock(SPIRVFunction *, SPIRVId);
- virtual SPIRVString *getString(const std::string &Str);
- virtual SPIRVMemberName *addMemberName(SPIRVTypeStruct *ST,
- SPIRVWord MemberNumber, const std::string &Name);
- virtual void addUnknownStructField(SPIRVTypeStruct *Struct, unsigned I,
- SPIRVId ID);
- virtual void addLine(SPIRVEntry *E, SPIRVId FileNameId, SPIRVWord Line,
- SPIRVWord Column);
- virtual const std::shared_ptr<const SPIRVLine>& getCurrentLine() const;
- virtual void setCurrentLine(const std::shared_ptr<const SPIRVLine> &Line);
- virtual void addCapability(SPIRVCapabilityKind);
- virtual void addCapabilityInternal(SPIRVCapabilityKind);
- virtual const SPIRVDecorateGeneric *addDecorate(SPIRVDecorateGeneric *);
- virtual SPIRVDecorationGroup *addDecorationGroup();
- virtual SPIRVDecorationGroup *addDecorationGroup(SPIRVDecorationGroup *Group);
- virtual SPIRVGroupDecorate *addGroupDecorate(SPIRVDecorationGroup *Group,
- const std::vector<SPIRVEntry *> &Targets);
- virtual SPIRVGroupDecorateGeneric *addGroupDecorateGeneric(
- SPIRVGroupDecorateGeneric *GDec);
- virtual SPIRVGroupMemberDecorate *addGroupMemberDecorate(
- SPIRVDecorationGroup *Group, const std::vector<SPIRVEntry *> &Targets);
- virtual void addEntryPoint(SPIRVExecutionModelKind ExecModel,
- SPIRVId EntryPoint);
- virtual SPIRVForward *addForward(SPIRVType *Ty);
- virtual SPIRVForward *addForward(SPIRVId, SPIRVType *Ty);
- virtual SPIRVFunction *addFunction(SPIRVFunction *);
- virtual SPIRVFunction *addFunction(SPIRVTypeFunction *, SPIRVId);
- virtual SPIRVEntry *replaceForward(SPIRVForward *, SPIRVEntry *);
- virtual void eraseInstruction(SPIRVInstruction *, SPIRVBasicBlock *);
-
- // Type creation functions
- template<class T> T * addType(T *Ty);
- virtual SPIRVTypeArray *addArrayType(SPIRVType *, SPIRVConstant *);
- virtual SPIRVTypeBool *addBoolType();
- virtual SPIRVTypeFloat *addFloatType(unsigned BitWidth);
- virtual SPIRVTypeFunction *addFunctionType(SPIRVType *,
- const std::vector<SPIRVType *> &);
- virtual SPIRVTypeInt *addIntegerType(unsigned BitWidth);
- virtual SPIRVTypeOpaque *addOpaqueType(const std::string &);
- virtual SPIRVTypePointer *addPointerType(SPIRVStorageClassKind, SPIRVType *);
- virtual SPIRVTypeImage *addImageType(SPIRVType *,
- const SPIRVTypeImageDescriptor &);
- virtual SPIRVTypeImage *addImageType(SPIRVType *,
- const SPIRVTypeImageDescriptor &, SPIRVAccessQualifierKind);
- virtual SPIRVTypeSampler *addSamplerType();
- virtual SPIRVTypePipeStorage *addPipeStorageType();
- virtual SPIRVTypeSampledImage *addSampledImageType(SPIRVTypeImage *T);
- virtual SPIRVTypeStruct *openStructType(unsigned, const std::string &);
- virtual void closeStructType(SPIRVTypeStruct *T, bool);
- virtual SPIRVTypeVector *addVectorType(SPIRVType *, SPIRVWord);
- virtual SPIRVType *addOpaqueGenericType(Op);
- virtual SPIRVTypeDeviceEvent *addDeviceEventType();
- virtual SPIRVTypeQueue *addQueueType();
- virtual SPIRVTypePipe *addPipeType();
- virtual SPIRVTypeVoid *addVoidType();
- virtual void createForwardPointers();
-
- // Constant creation functions
- virtual SPIRVInstruction *addBranchInst(SPIRVLabel *, SPIRVBasicBlock *);
- virtual SPIRVInstruction *addBranchConditionalInst(SPIRVValue *, SPIRVLabel *,
- SPIRVLabel *, SPIRVBasicBlock *);
- virtual SPIRVValue *addCompositeConstant(SPIRVType *,
- const std::vector<SPIRVValue*>&);
- virtual SPIRVValue *addConstant(SPIRVValue *);
- virtual SPIRVValue *addConstant(SPIRVType *, uint64_t);
- virtual SPIRVValue *addDoubleConstant(SPIRVTypeFloat *, double);
- virtual SPIRVValue *addFloatConstant(SPIRVTypeFloat *, float);
- virtual SPIRVValue *addIntegerConstant(SPIRVTypeInt *, uint64_t);
- virtual SPIRVValue *addNullConstant(SPIRVType *);
- virtual SPIRVValue *addUndef(SPIRVType *TheType);
- virtual SPIRVValue *addSamplerConstant(SPIRVType *TheType, SPIRVWord AddrMode,
- SPIRVWord ParametricMode, SPIRVWord FilterMode);
- virtual SPIRVValue* addPipeStorageConstant(SPIRVType* TheType,
- SPIRVWord PacketSize, SPIRVWord PacketAlign, SPIRVWord Capacity);
-
- // Instruction creation functions
- virtual SPIRVInstruction *addPtrAccessChainInst(SPIRVType *, SPIRVValue *,
- std::vector<SPIRVValue *>, SPIRVBasicBlock *, bool);
- virtual SPIRVInstruction *addAsyncGroupCopy(SPIRVValue *Scope,
- SPIRVValue *Dest, SPIRVValue *Src, SPIRVValue *NumElems, SPIRVValue *Stride,
- SPIRVValue *Event, SPIRVBasicBlock *BB);
- virtual SPIRVInstruction *addExtInst(SPIRVType *,
- SPIRVWord, SPIRVWord, const std::vector<SPIRVWord> &,
- SPIRVBasicBlock *);
- virtual SPIRVInstruction *addExtInst(SPIRVType *,
- SPIRVWord, SPIRVWord, const std::vector<SPIRVValue *> &,
- SPIRVBasicBlock *);
- virtual SPIRVInstruction *addBinaryInst(Op, SPIRVType *, SPIRVValue *,
- SPIRVValue *, SPIRVBasicBlock *);
- virtual SPIRVInstruction *addCallInst(SPIRVFunction*,
- const std::vector<SPIRVWord> &, SPIRVBasicBlock *);
- virtual SPIRVInstruction *addCmpInst(Op, SPIRVType *, SPIRVValue *,
- SPIRVValue *, SPIRVBasicBlock *);
- virtual SPIRVInstruction *addLoadInst(SPIRVValue *,
- const std::vector<SPIRVWord>&, SPIRVBasicBlock *);
- virtual SPIRVInstruction *addPhiInst(SPIRVType *, std::vector<SPIRVValue *>,
- SPIRVBasicBlock *);
- virtual SPIRVInstruction *addCompositeConstructInst(SPIRVType *,
- const std::vector<SPIRVId>&, SPIRVBasicBlock *);
- virtual SPIRVInstruction *addCompositeExtractInst(SPIRVType *, SPIRVValue *,
- const std::vector<SPIRVWord>&, SPIRVBasicBlock *);
- virtual SPIRVInstruction *addCompositeInsertInst(SPIRVValue *Object,
- SPIRVValue *Composite, const std::vector<SPIRVWord>& Indices,
- SPIRVBasicBlock *BB);
- virtual SPIRVInstruction *addCopyObjectInst(SPIRVType *TheType,
- SPIRVValue *Operand, SPIRVBasicBlock *BB);
- virtual SPIRVInstruction *addCopyMemoryInst(SPIRVValue *, SPIRVValue *,
- const std::vector<SPIRVWord>&, SPIRVBasicBlock *);
- virtual SPIRVInstruction *addCopyMemorySizedInst(SPIRVValue *, SPIRVValue *,
- SPIRVValue *, const std::vector<SPIRVWord>&, SPIRVBasicBlock *);
- virtual SPIRVInstruction *addControlBarrierInst(
- SPIRVValue *ExecKind, SPIRVValue *MemKind,
- SPIRVValue *MemSema, SPIRVBasicBlock *BB);
- virtual SPIRVInstruction *addGroupInst(Op OpCode, SPIRVType *Type,
- Scope Scope, const std::vector<SPIRVValue *> &Ops,
- SPIRVBasicBlock *BB);
- virtual SPIRVInstruction *addInstruction(SPIRVInstruction *Inst,
- SPIRVBasicBlock *BB);
- virtual SPIRVInstTemplateBase *addInstTemplate(Op OC,
- SPIRVBasicBlock* BB, SPIRVType *Ty);
- virtual SPIRVInstTemplateBase *addInstTemplate(Op OC,
- const std::vector<SPIRVWord>& Ops, SPIRVBasicBlock* BB, SPIRVType *Ty);
- virtual SPIRVInstruction *addLifetimeInst(Op OC, SPIRVValue *Object,
- SPIRVWord Size, SPIRVBasicBlock *BB);
- virtual SPIRVInstruction *addMemoryBarrierInst(
- Scope ScopeKind, SPIRVWord MemFlag, SPIRVBasicBlock *BB);
- virtual SPIRVInstruction *addUnreachableInst(SPIRVBasicBlock *);
- virtual SPIRVInstruction *addReturnInst(SPIRVBasicBlock *);
- virtual SPIRVInstruction *addReturnValueInst(SPIRVValue *, SPIRVBasicBlock *);
- virtual SPIRVInstruction *addSelectInst(SPIRVValue *, SPIRVValue *, SPIRVValue *,
- SPIRVBasicBlock *);
- virtual SPIRVInstruction *addLoopMergeInst(SPIRVId MergeBlock,
- SPIRVId ContinueTarget, SPIRVWord LoopControl, SPIRVBasicBlock *BB);
- virtual SPIRVInstruction *addSelectionMergeInst(SPIRVId MergeBlock,
- SPIRVWord SelectionControl, SPIRVBasicBlock *BB);
- virtual SPIRVInstruction *addStoreInst(SPIRVValue *, SPIRVValue *,
- const std::vector<SPIRVWord>&, SPIRVBasicBlock *);
- virtual SPIRVInstruction *addSwitchInst(SPIRVValue *, SPIRVBasicBlock *,
- const std::vector<std::pair<std::vector<SPIRVWord>, SPIRVBasicBlock *>>&,
- SPIRVBasicBlock *);
- virtual SPIRVInstruction *addFModInst(SPIRVType *TheType, SPIRVId TheDividend,
- SPIRVId TheDivisor, SPIRVBasicBlock *BB);
- virtual SPIRVInstruction *addVectorTimesScalarInst(SPIRVType *TheType,
- SPIRVId TheVector, SPIRVId TheScalar, SPIRVBasicBlock *BB);
- virtual SPIRVInstruction *addUnaryInst(Op, SPIRVType *, SPIRVValue *,
- SPIRVBasicBlock *);
- virtual SPIRVInstruction *addVariable(SPIRVType *, bool, SPIRVLinkageTypeKind,
- SPIRVValue *, const std::string &, SPIRVStorageClassKind, SPIRVBasicBlock *);
- virtual SPIRVValue *addVectorShuffleInst(SPIRVType *Type, SPIRVValue *Vec1,
- SPIRVValue *Vec2, const std::vector<SPIRVWord> &Components,
- SPIRVBasicBlock *BB);
- virtual SPIRVInstruction *addVectorExtractDynamicInst(SPIRVValue *,
- SPIRVValue *, SPIRVBasicBlock *);
- virtual SPIRVInstruction *addVectorInsertDynamicInst(SPIRVValue *,
- SPIRVValue *, SPIRVValue*, SPIRVBasicBlock *);
-
- // I/O functions
- friend spv_ostream & operator<<(spv_ostream &O, SPIRVModule& M);
- friend std::istream & operator>>(std::istream &I, SPIRVModule& M);
-
-private:
- SPIRVErrorLog ErrLog;
- SPIRVId NextId;
- SPIRVTypeInt *BoolType;
- SPIRVWord SPIRVVersion;
- unsigned short GeneratorId;
- unsigned short GeneratorVer;
- SPIRVInstructionSchemaKind InstSchema;
- SourceLanguage SrcLang;
- SPIRVWord SrcLangVer;
- std::set<std::string> SrcExtension;
- std::set<std::string> SPIRVExt;
- SPIRVAddressingModelKind AddrModel;
- SPIRVMemoryModelKind MemoryModel;
-
- typedef std::map<SPIRVId, SPIRVEntry *> SPIRVIdToEntryMap;
- typedef std::set<SPIRVEntry *> SPIRVEntrySet;
- typedef std::set<SPIRVId> SPIRVIdSet;
- typedef std::vector<SPIRVId> SPIRVIdVec;
- typedef std::vector<SPIRVFunction *> SPIRVFunctionVector;
- typedef std::vector<SPIRVTypeForwardPointer *> SPIRVForwardPointerVec;
- typedef std::vector<SPIRVType *> SPIRVTypeVec;
- typedef std::vector<SPIRVValue *> SPIRVConstantVector;
- typedef std::vector<SPIRVVariable *> SPIRVVariableVec;
- typedef std::vector<SPIRVString *> SPIRVStringVec;
- typedef std::vector<SPIRVMemberName *> SPIRVMemberNameVec;
- typedef std::vector<SPIRVDecorationGroup *> SPIRVDecGroupVec;
- typedef std::vector<SPIRVGroupDecorateGeneric *> SPIRVGroupDecVec;
- typedef std::map<SPIRVId, SPIRVExtInstSetKind> SPIRVIdToBuiltinSetMap;
- typedef std::map<SPIRVExecutionModelKind, SPIRVIdSet> SPIRVExecModelIdSetMap;
- typedef std::map<SPIRVExecutionModelKind, SPIRVIdVec> SPIRVExecModelIdVecMap;
- typedef std::unordered_map<std::string, SPIRVString*> SPIRVStringMap;
- typedef std::map<SPIRVTypeStruct *, std::vector<std::pair<unsigned, SPIRVId>>>
- SPIRVUnknownStructFieldMap;
-
- SPIRVForwardPointerVec ForwardPointerVec;
- SPIRVTypeVec TypeVec;
- SPIRVIdToEntryMap IdEntryMap;
- SPIRVFunctionVector FuncVec;
- SPIRVConstantVector ConstVec;
- SPIRVVariableVec VariableVec;
- SPIRVEntrySet EntryNoId; // Entries without id
- SPIRVIdToBuiltinSetMap IdBuiltinMap;
- SPIRVIdSet NamedId;
- SPIRVStringVec StringVec;
- SPIRVMemberNameVec MemberNameVec;
- std::shared_ptr<const SPIRVLine> CurrentLine;
- SPIRVDecorateSet DecorateSet;
- SPIRVDecGroupVec DecGroupVec;
- SPIRVGroupDecVec GroupDecVec;
- SPIRVExecModelIdSetMap EntryPointSet;
- SPIRVExecModelIdVecMap EntryPointVec;
- SPIRVStringMap StrMap;
- SPIRVCapMap CapMap;
- SPIRVUnknownStructFieldMap UnknownStructFieldMap;
- std::map<unsigned, SPIRVTypeInt*> IntTypeMap;
- std::map<unsigned, SPIRVConstant*> LiteralMap;
-
- void layoutEntry(SPIRVEntry* Entry);
-};
-
-SPIRVModuleImpl::~SPIRVModuleImpl() {
- for (auto I : EntryNoId)
- delete I;
-
- for (auto I : IdEntryMap)
- delete I.second;
-
- for (auto C : CapMap)
- delete C.second;
-}
-
-const std::shared_ptr<const SPIRVLine>&
-SPIRVModuleImpl::getCurrentLine() const {
- return CurrentLine;
-}
-
-void
-SPIRVModuleImpl::setCurrentLine(const std::shared_ptr<const SPIRVLine>& Line) {
- CurrentLine = Line;
-}
-
-void
-SPIRVModuleImpl::addLine(SPIRVEntry* E, SPIRVId FileNameId,
- SPIRVWord Line, SPIRVWord Column) {
- if (!(CurrentLine && CurrentLine->equals(FileNameId, Line, Column)))
- CurrentLine.reset(new SPIRVLine(this, FileNameId, Line, Column));
- assert(E && "invalid entry");
- E->setLine(CurrentLine);
-}
-
-// Creates decoration group and group decorates from decorates shared by
-// multiple targets.
-void
-SPIRVModuleImpl::optimizeDecorates() {
- SPIRVDBG(spvdbgs() << "[optimizeDecorates] begin\n");
- for (auto I = DecorateSet.begin(), E = DecorateSet.end(); I != E;) {
- auto D = *I;
- SPIRVDBG(spvdbgs() << " check " << *D << '\n');
- if (D->getOpCode() == OpMemberDecorate) {
- ++I;
- continue;
- }
- auto ER = DecorateSet.equal_range(D);
- SPIRVDBG(spvdbgs() << " equal range " << **ER.first
- << " to ";
- if (ER.second != DecorateSet.end())
- spvdbgs() << **ER.second;
- else
- spvdbgs() << "end";
- spvdbgs() << '\n');
- if (std::distance(ER.first, ER.second) < 2) {
- I = ER.second;
- SPIRVDBG(spvdbgs() << " skip equal range \n");
- continue;
- }
- SPIRVDBG(spvdbgs() << " add deco group. erase equal range\n");
- auto G = add(new SPIRVDecorationGroup(this, getId()));
- std::vector<SPIRVId> Targets;
- Targets.push_back(D->getTargetId());
- const_cast<SPIRVDecorateGeneric*>(D)->setTargetId(G->getId());
- G->getDecorations().insert(D);
- for (I = ER.first; I != ER.second; ++I) {
- auto E = *I;
- if (*E == *D)
- continue;
- Targets.push_back(E->getTargetId());
- }
-
- // WordCount is only 16 bits. We can only have 65535 - FixedWC targtets per
- // group.
- // For now, just skip using a group if the number of targets to too big
- if (Targets.size() < 65530) {
- DecorateSet.erase(ER.first, ER.second);
- auto GD = add(new SPIRVGroupDecorate(G, Targets));
- DecGroupVec.push_back(G);
- GroupDecVec.push_back(GD);
- }
- }
-}
-
-SPIRVValue*
-SPIRVModuleImpl::addSamplerConstant(SPIRVType* TheType,
- SPIRVWord AddrMode, SPIRVWord ParametricMode, SPIRVWord FilterMode) {
- return addConstant(new SPIRVConstantSampler(this, TheType, getId(), AddrMode,
- ParametricMode, FilterMode));
-}
-
-SPIRVValue*
-SPIRVModuleImpl::addPipeStorageConstant(SPIRVType* TheType,
- SPIRVWord PacketSize, SPIRVWord PacketAlign, SPIRVWord Capacity) {
- return addConstant(new SPIRVConstantPipeStorage(this, TheType, getId(),
- PacketSize, PacketAlign, Capacity));
-}
-
-void
-SPIRVModuleImpl::addCapability(SPIRVCapabilityKind Cap) {
- addCapabilities(SPIRV::getCapability(Cap));
- SPIRVDBG(spvdbgs() << "addCapability: " << Cap << '\n');
- if (hasCapability(Cap))
- return;
-
- CapMap.insert(std::make_pair(Cap, new SPIRVCapability(this, Cap)));
-}
-
-void
-SPIRVModuleImpl::addCapabilityInternal(SPIRVCapabilityKind Cap) {
- if (AutoAddCapability) {
- if (hasCapability(Cap))
- return;
-
- CapMap.insert(std::make_pair(Cap, new SPIRVCapability(this, Cap)));
- }
-}
-
-SPIRVConstant*
-SPIRVModuleImpl::getLiteralAsConstant(unsigned Literal) {
- auto Loc = LiteralMap.find(Literal);
- if (Loc != LiteralMap.end())
- return Loc->second;
- auto Ty = addIntegerType(32);
- auto V = new SPIRVConstant(this, Ty, getId(), static_cast<uint64_t>(Literal));
- LiteralMap[Literal] = V;
- addConstant(V);
- return V;
-}
-
-void
-SPIRVModuleImpl::layoutEntry(SPIRVEntry* E) {
- auto OC = E->getOpCode();
- switch (OC) {
- case OpString:
- addTo(StringVec, E);
- break;
- case OpMemberName:
- addTo(MemberNameVec, E);
- break;
- case OpVariable: {
- auto BV = static_cast<SPIRVVariable*>(E);
- if (!BV->getParent())
- addTo(VariableVec, E);
- }
- break;
- default:
- if (isTypeOpCode(OC))
- TypeVec.push_back(static_cast<SPIRVType*>(E));
- else if (isConstantOpCode(OC))
- ConstVec.push_back(static_cast<SPIRVConstant*>(E));
- break;
- }
-}
-
-// Add an entry to the id to entry map.
-// Assert if the id is mapped to a different entry.
-// Certain entries need to be add to specific collectors to maintain
-// logic layout of SPIRV.
-SPIRVEntry *
-SPIRVModuleImpl::addEntry(SPIRVEntry *Entry) {
- assert(Entry && "Invalid entry");
- if (Entry->hasId()) {
- SPIRVId Id = Entry->getId();
- assert(Entry->getId() != SPIRVID_INVALID && "Invalid id");
- SPIRVEntry *Mapped = nullptr;
- if (exist(Id, &Mapped)) {
- if (Mapped->getOpCode() == OpForward) {
- replaceForward(static_cast<SPIRVForward *>(Mapped), Entry);
- } else {
- assert(Mapped == Entry && "Id used twice");
- }
- } else
- IdEntryMap[Id] = Entry;
- } else {
- // Entry of OpLine will be deleted by std::shared_ptr automatically.
- if (Entry->getOpCode() != OpLine)
- EntryNoId.insert(Entry);
- }
-
- Entry->setModule(this);
-
- layoutEntry(Entry);
- if (AutoAddCapability) {
- for (auto &I:Entry->getRequiredCapability()) {
- addCapability(I);
- }
- }
- if (ValidateCapability) {
- assert(none_of(
- Entry->getRequiredCapability().begin(),
- Entry->getRequiredCapability().end(),
- [this](SPIRVCapabilityKind &val) { return !CapMap.count(val); }));
- }
- return Entry;
-}
-
-bool
-SPIRVModuleImpl::exist(SPIRVId Id) const {
- return exist(Id, nullptr);
-}
-
-bool
-SPIRVModuleImpl::exist(SPIRVId Id, SPIRVEntry **Entry) const {
- assert (Id != SPIRVID_INVALID && "Invalid Id");
- SPIRVIdToEntryMap::const_iterator Loc = IdEntryMap.find(Id);
- if (Loc == IdEntryMap.end())
- return false;
- if (Entry)
- *Entry = Loc->second;
- return true;
-}
-
-// If Id is invalid, returns the next available id.
-// Otherwise returns the given id and adjust the next available id by increment.
-SPIRVId
-SPIRVModuleImpl::getId(SPIRVId Id, unsigned increment) {
- if (!isValidId(Id))
- Id = NextId;
- else
- NextId = std::max(Id, NextId);
- NextId += increment;
- return Id;
-}
-
-SPIRVEntry *
-SPIRVModuleImpl::getEntry(SPIRVId Id) const {
- assert (Id != SPIRVID_INVALID && "Invalid Id");
- SPIRVIdToEntryMap::const_iterator Loc = IdEntryMap.find(Id);
- assert (Loc != IdEntryMap.end() && "Id is not in map");
- return Loc->second;
-}
-
-SPIRVExtInstSetKind
-SPIRVModuleImpl::getBuiltinSet(SPIRVId SetId) const {
- auto Loc = IdBuiltinMap.find(SetId);
- assert(Loc != IdBuiltinMap.end() && "Invalid builtin set id");
- return Loc->second;
-}
-
-bool
-SPIRVModuleImpl::isEntryPoint(SPIRVExecutionModelKind ExecModel, SPIRVId EP)
- const {
- assert(isValid(ExecModel) && "Invalid execution model");
- assert(EP != SPIRVID_INVALID && "Invalid function id");
- auto Loc = EntryPointSet.find(ExecModel);
- if (Loc == EntryPointSet.end())
- return false;
- return Loc->second.count(EP);
-}
-
-// Module change functions
-bool
-SPIRVModuleImpl::importBuiltinSet(const std::string& BuiltinSetName,
- SPIRVId *BuiltinSetId) {
- SPIRVId TmpBuiltinSetId = getId();
- if (!importBuiltinSetWithId(BuiltinSetName, TmpBuiltinSetId))
- return false;
- if (BuiltinSetId)
- *BuiltinSetId = TmpBuiltinSetId;
- return true;
-}
-
-bool
-SPIRVModuleImpl::importBuiltinSetWithId(const std::string& BuiltinSetName,
- SPIRVId BuiltinSetId) {
- SPIRVExtInstSetKind BuiltinSet = SPIRVEIS_Count;
- SPIRVCKRT(SPIRVBuiltinSetNameMap::rfind(BuiltinSetName, &BuiltinSet),
- InvalidBuiltinSetName, "Actual is " + BuiltinSetName);
- IdBuiltinMap[BuiltinSetId] = BuiltinSet;
- return true;
-}
-
-void
-SPIRVModuleImpl::setAlignment(SPIRVValue *V, SPIRVWord A) {
- V->setAlignment(A);
-}
-
-void
-SPIRVModuleImpl::setName(SPIRVEntry *E, const std::string &Name) {
- E->setName(Name);
- if (!E->hasId())
- return;
- if (!Name.empty())
- NamedId.insert(E->getId());
- else
- NamedId.erase(E->getId());
-}
-
-void SPIRVModuleImpl::resolveUnknownStructFields() {
- for (auto &KV : UnknownStructFieldMap) {
- auto *Struct = KV.first;
- for (auto &Indices : KV.second) {
- unsigned I = Indices.first;
- SPIRVId ID = Indices.second;
-
- auto Ty = static_cast<SPIRVType *>(getEntry(ID));
- Struct->setMemberType(I, Ty);
- }
- }
-}
-
-// Type creation functions
-template<class T>
-T *
-SPIRVModuleImpl::addType(T *Ty) {
- add(Ty);
- if (!Ty->getName().empty())
- setName(Ty, Ty->getName());
- return Ty;
-}
-
-SPIRVTypeVoid *
-SPIRVModuleImpl::addVoidType() {
- return addType(new SPIRVTypeVoid(this, getId()));
-}
-
-SPIRVTypeArray *
-SPIRVModuleImpl::addArrayType(SPIRVType *ElementType, SPIRVConstant *Length) {
- return addType(new SPIRVTypeArray(this, getId(), ElementType, Length));
-}
-
-SPIRVTypeBool *
-SPIRVModuleImpl::addBoolType() {
- return addType(new SPIRVTypeBool(this, getId()));
-}
-
-SPIRVTypeInt *
-SPIRVModuleImpl::addIntegerType(unsigned BitWidth) {
- auto Loc = IntTypeMap.find(BitWidth);
- if (Loc != IntTypeMap.end())
- return Loc->second;
- auto Ty = new SPIRVTypeInt(this, getId(), BitWidth, false);
- IntTypeMap[BitWidth] = Ty;
- return addType(Ty);
-}
-
-SPIRVTypeFloat *
-SPIRVModuleImpl::addFloatType(unsigned BitWidth) {
- SPIRVTypeFloat *T = addType(new SPIRVTypeFloat(this, getId(), BitWidth));
- return T;
-}
-
-SPIRVTypePointer *
-SPIRVModuleImpl::addPointerType(SPIRVStorageClassKind StorageClass,
- SPIRVType *ElementType) {
- return addType(new SPIRVTypePointer(this, getId(), StorageClass,
- ElementType));
-}
-
-SPIRVTypeFunction *
-SPIRVModuleImpl::addFunctionType(SPIRVType *ReturnType,
- const std::vector<SPIRVType *>& ParameterTypes) {
- return addType(new SPIRVTypeFunction(this, getId(), ReturnType,
- ParameterTypes));
-}
-
-SPIRVTypeOpaque*
-SPIRVModuleImpl::addOpaqueType(const std::string& Name) {
- return addType(new SPIRVTypeOpaque(this, getId(), Name));
-}
-
-SPIRVTypeStruct *SPIRVModuleImpl::openStructType(unsigned NumMembers,
- const std::string &Name) {
- auto T = new SPIRVTypeStruct(this, getId(), NumMembers, Name);
- return T;
-}
-
-void SPIRVModuleImpl::closeStructType(SPIRVTypeStruct *T, bool Packed) {
- addType(T);
- T->setPacked(Packed);
-}
-
-SPIRVTypeVector*
-SPIRVModuleImpl::addVectorType(SPIRVType* CompType, SPIRVWord CompCount) {
- return addType(new SPIRVTypeVector(this, getId(), CompType, CompCount));
-}
-SPIRVType *
-SPIRVModuleImpl::addOpaqueGenericType(Op TheOpCode) {
- return addType(new SPIRVTypeOpaqueGeneric(TheOpCode, this, getId()));
-}
-
-SPIRVTypeDeviceEvent *
-SPIRVModuleImpl::addDeviceEventType() {
- return addType(new SPIRVTypeDeviceEvent(this, getId()));
-}
-
-SPIRVTypeQueue *
-SPIRVModuleImpl::addQueueType() {
- return addType(new SPIRVTypeQueue(this, getId()));
-}
-
-SPIRVTypePipe*
-SPIRVModuleImpl::addPipeType() {
- return addType(new SPIRVTypePipe(this, getId()));
-}
-
-SPIRVTypeImage *
-SPIRVModuleImpl::addImageType(SPIRVType *SampledType,
- const SPIRVTypeImageDescriptor &Desc) {
- return addType(new SPIRVTypeImage(this, getId(),
- SampledType ? SampledType->getId() : 0, Desc));
-}
-
-SPIRVTypeImage *
-SPIRVModuleImpl::addImageType(SPIRVType *SampledType,
- const SPIRVTypeImageDescriptor &Desc, SPIRVAccessQualifierKind Acc) {
- return addType(new SPIRVTypeImage(this, getId(),
- SampledType ? SampledType->getId() : 0, Desc, Acc));
-}
-
-SPIRVTypeSampler *
-SPIRVModuleImpl::addSamplerType() {
- return addType(new SPIRVTypeSampler(this, getId()));
-}
-
-SPIRVTypePipeStorage*
-SPIRVModuleImpl::addPipeStorageType() {
- return addType(new SPIRVTypePipeStorage(this, getId()));
-}
-
-SPIRVTypeSampledImage *
-SPIRVModuleImpl::addSampledImageType(SPIRVTypeImage *T) {
- return addType(new SPIRVTypeSampledImage(this, getId(), T));
-}
-
-void SPIRVModuleImpl::createForwardPointers() {
- std::unordered_set<SPIRVId> Seen;
-
- for (auto *T : TypeVec) {
- if (T->hasId())
- Seen.insert(T->getId());
-
- if (!T->isTypeStruct())
- continue;
-
- auto ST = static_cast<SPIRVTypeStruct *>(T);
-
- for (unsigned i = 0; i < ST->getStructMemberCount(); ++i) {
- auto MemberTy = ST->getStructMemberType(i);
- if (!MemberTy->isTypePointer()) continue;
- auto Ptr = static_cast<SPIRVTypePointer *>(MemberTy);
-
- if (Seen.find(Ptr->getId()) == Seen.end()) {
- ForwardPointerVec.push_back(new SPIRVTypeForwardPointer(
- this, Ptr, Ptr->getPointerStorageClass()));
- }
- }
- }
-}
-
-SPIRVFunction *
-SPIRVModuleImpl::addFunction(SPIRVFunction *Func) {
- FuncVec.push_back(add(Func));
- return Func;
-}
-
-SPIRVFunction *
-SPIRVModuleImpl::addFunction(SPIRVTypeFunction *FuncType, SPIRVId Id) {
- return addFunction(new SPIRVFunction(this, FuncType,
- getId(Id, FuncType->getNumParameters() + 1)));
-}
-
-SPIRVBasicBlock *
-SPIRVModuleImpl::addBasicBlock(SPIRVFunction *Func, SPIRVId Id) {
- return Func->addBasicBlock(new SPIRVBasicBlock(getId(Id), Func));
-}
-
-const SPIRVDecorateGeneric *
-SPIRVModuleImpl::addDecorate(SPIRVDecorateGeneric *Dec) {
- add(Dec);
- SPIRVId Id = Dec->getTargetId();
- bool Found = exist(Id);
+//===- SPIRVModule.cpp - Class to represent SPIR-V module --------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file implements Module class for SPIR-V. +/// +//===----------------------------------------------------------------------===// + +#include "SPIRVModule.h" +#include "SPIRVDebug.h" +#include "SPIRVEntry.h" +#include "SPIRVType.h" +#include "SPIRVValue.h" +#include "SPIRVExtInst.h" +#include "SPIRVFunction.h" +#include "SPIRVInstruction.h" +#include "SPIRVStream.h" + +#include <set> +#include <unordered_map> +#include <unordered_set> + +namespace SPIRV{ + +SPIRVModule::SPIRVModule():AutoAddCapability(true), ValidateCapability(false) +{} + +SPIRVModule::~SPIRVModule() +{} + +class SPIRVModuleImpl : public SPIRVModule { +public: + SPIRVModuleImpl():SPIRVModule(), NextId(1), BoolType(NULL), + SPIRVVersion(SPIRV_1_0), + GeneratorId(SPIRVGEN_KhronosLLVMSPIRVTranslator), + GeneratorVer(0), + InstSchema(SPIRVISCH_Default), + SrcLang(SourceLanguageOpenCL_C), + SrcLangVer(102000) { + AddrModel = sizeof(size_t) == 32 ? AddressingModelPhysical32 + : AddressingModelPhysical64; + // OpenCL memory model requires Kernel capability + setMemoryModel(MemoryModelOpenCL); + } + virtual ~SPIRVModuleImpl(); + + // Object query functions + bool exist(SPIRVId) const; + bool exist(SPIRVId, SPIRVEntry **) const; + SPIRVId getId(SPIRVId Id = SPIRVID_INVALID, unsigned Increment = 1); + virtual SPIRVEntry *getEntry(SPIRVId Id) const; + bool hasDebugInfo() const { return !StringVec.empty();} + + // Error handling functions + SPIRVErrorLog &getErrorLog() { return ErrLog;} + SPIRVErrorCode getError(std::string &ErrMsg) { return ErrLog.getError(ErrMsg);} + + // Module query functions + SPIRVAddressingModelKind getAddressingModel() { return AddrModel;} + SPIRVExtInstSetKind getBuiltinSet(SPIRVId SetId) const; + const SPIRVCapMap &getCapability() const { return CapMap; } + bool hasCapability(SPIRVCapabilityKind Cap) const { + return CapMap.find(Cap) != CapMap.end(); + } + std::set<std::string> &getExtension() { return SPIRVExt;} + SPIRVFunction *getFunction(unsigned I) const { return FuncVec[I];} + SPIRVVariable *getVariable(unsigned I) const { return VariableVec[I];} + virtual SPIRVValue *getValue(SPIRVId TheId) const; + virtual std::vector<SPIRVValue *> getValues(const std::vector<SPIRVId>&)const; + virtual std::vector<SPIRVId> getIds(const std::vector<SPIRVEntry *>&)const; + virtual std::vector<SPIRVId> getIds(const std::vector<SPIRVValue *>&)const; + virtual SPIRVType *getValueType(SPIRVId TheId)const; + virtual std::vector<SPIRVType *> getValueTypes(const std::vector<SPIRVId>&) + const; + SPIRVMemoryModelKind getMemoryModel() const { return MemoryModel;} + virtual SPIRVConstant* getLiteralAsConstant(unsigned Literal); + unsigned getNumEntryPoints(SPIRVExecutionModelKind EM) const { + auto Loc = EntryPointVec.find(EM); + if (Loc == EntryPointVec.end()) + return 0; + return Loc->second.size(); + } + SPIRVFunction *getEntryPoint(SPIRVExecutionModelKind EM, unsigned I) const { + auto Loc = EntryPointVec.find(EM); + if (Loc == EntryPointVec.end()) + return nullptr; + assert(I < Loc->second.size()); + return get<SPIRVFunction>(Loc->second[I]); + } + unsigned getNumFunctions() const { return FuncVec.size();} + unsigned getNumVariables() const { return VariableVec.size();} + SourceLanguage getSourceLanguage(SPIRVWord * Ver = nullptr) const { + if (Ver) + *Ver = SrcLangVer; + return SrcLang; + } + std::set<std::string> &getSourceExtension() { return SrcExtension;} + bool isEntryPoint(SPIRVExecutionModelKind, SPIRVId EP) const; + unsigned short getGeneratorId() const { return GeneratorId; } + unsigned short getGeneratorVer() const { return GeneratorVer; } + SPIRVWord getSPIRVVersion() const { return SPIRVVersion; } + + // Module changing functions + bool importBuiltinSet(const std::string &, SPIRVId *); + bool importBuiltinSetWithId(const std::string &, SPIRVId); + void optimizeDecorates(); + void setAddressingModel(SPIRVAddressingModelKind AM) { AddrModel = AM;} + void setAlignment(SPIRVValue *, SPIRVWord); + void setMemoryModel(SPIRVMemoryModelKind MM) { + MemoryModel = MM; + if (MemoryModel == spv::MemoryModelOpenCL) + addCapability(CapabilityKernel); + } + void setName(SPIRVEntry *E, const std::string &Name); + void setSourceLanguage(SourceLanguage Lang, SPIRVWord Ver) { + SrcLang = Lang; + SrcLangVer = Ver; + } + void setGeneratorId(unsigned short Id) { GeneratorId = Id; } + void setGeneratorVer(unsigned short Ver) { GeneratorVer = Ver; } + void resolveUnknownStructFields(); + + void setSPIRVVersion(SPIRVWord Ver) override { SPIRVVersion = Ver; } + + // Object creation functions + template<class T> void addTo(std::vector<T *> &V, SPIRVEntry *E); + virtual SPIRVEntry *addEntry(SPIRVEntry *E); + virtual SPIRVBasicBlock *addBasicBlock(SPIRVFunction *, SPIRVId); + virtual SPIRVString *getString(const std::string &Str); + virtual SPIRVMemberName *addMemberName(SPIRVTypeStruct *ST, + SPIRVWord MemberNumber, const std::string &Name); + virtual void addUnknownStructField(SPIRVTypeStruct *Struct, unsigned I, + SPIRVId ID); + virtual void addLine(SPIRVEntry *E, SPIRVId FileNameId, SPIRVWord Line, + SPIRVWord Column); + virtual const std::shared_ptr<const SPIRVLine>& getCurrentLine() const; + virtual void setCurrentLine(const std::shared_ptr<const SPIRVLine> &Line); + virtual void addCapability(SPIRVCapabilityKind); + virtual void addCapabilityInternal(SPIRVCapabilityKind); + virtual const SPIRVDecorateGeneric *addDecorate(SPIRVDecorateGeneric *); + virtual SPIRVDecorationGroup *addDecorationGroup(); + virtual SPIRVDecorationGroup *addDecorationGroup(SPIRVDecorationGroup *Group); + virtual SPIRVGroupDecorate *addGroupDecorate(SPIRVDecorationGroup *Group, + const std::vector<SPIRVEntry *> &Targets); + virtual SPIRVGroupDecorateGeneric *addGroupDecorateGeneric( + SPIRVGroupDecorateGeneric *GDec); + virtual SPIRVGroupMemberDecorate *addGroupMemberDecorate( + SPIRVDecorationGroup *Group, const std::vector<SPIRVEntry *> &Targets); + virtual void addEntryPoint(SPIRVExecutionModelKind ExecModel, + SPIRVId EntryPoint); + virtual SPIRVForward *addForward(SPIRVType *Ty); + virtual SPIRVForward *addForward(SPIRVId, SPIRVType *Ty); + virtual SPIRVFunction *addFunction(SPIRVFunction *); + virtual SPIRVFunction *addFunction(SPIRVTypeFunction *, SPIRVId); + virtual SPIRVEntry *replaceForward(SPIRVForward *, SPIRVEntry *); + virtual void eraseInstruction(SPIRVInstruction *, SPIRVBasicBlock *); + + // Type creation functions + template<class T> T * addType(T *Ty); + virtual SPIRVTypeArray *addArrayType(SPIRVType *, SPIRVConstant *); + virtual SPIRVTypeBool *addBoolType(); + virtual SPIRVTypeFloat *addFloatType(unsigned BitWidth); + virtual SPIRVTypeFunction *addFunctionType(SPIRVType *, + const std::vector<SPIRVType *> &); + virtual SPIRVTypeInt *addIntegerType(unsigned BitWidth); + virtual SPIRVTypeOpaque *addOpaqueType(const std::string &); + virtual SPIRVTypePointer *addPointerType(SPIRVStorageClassKind, SPIRVType *); + virtual SPIRVTypeImage *addImageType(SPIRVType *, + const SPIRVTypeImageDescriptor &); + virtual SPIRVTypeImage *addImageType(SPIRVType *, + const SPIRVTypeImageDescriptor &, SPIRVAccessQualifierKind); + virtual SPIRVTypeSampler *addSamplerType(); + virtual SPIRVTypePipeStorage *addPipeStorageType(); + virtual SPIRVTypeSampledImage *addSampledImageType(SPIRVTypeImage *T); + virtual SPIRVTypeStruct *openStructType(unsigned, const std::string &); + virtual void closeStructType(SPIRVTypeStruct *T, bool); + virtual SPIRVTypeVector *addVectorType(SPIRVType *, SPIRVWord); + virtual SPIRVType *addOpaqueGenericType(Op); + virtual SPIRVTypeDeviceEvent *addDeviceEventType(); + virtual SPIRVTypeQueue *addQueueType(); + virtual SPIRVTypePipe *addPipeType(); + virtual SPIRVTypeVoid *addVoidType(); + virtual void createForwardPointers(); + + // Constant creation functions + virtual SPIRVInstruction *addBranchInst(SPIRVLabel *, SPIRVBasicBlock *); + virtual SPIRVInstruction *addBranchConditionalInst(SPIRVValue *, SPIRVLabel *, + SPIRVLabel *, SPIRVBasicBlock *); + virtual SPIRVValue *addCompositeConstant(SPIRVType *, + const std::vector<SPIRVValue*>&); + virtual SPIRVValue *addConstant(SPIRVValue *); + virtual SPIRVValue *addConstant(SPIRVType *, uint64_t); + virtual SPIRVValue *addDoubleConstant(SPIRVTypeFloat *, double); + virtual SPIRVValue *addFloatConstant(SPIRVTypeFloat *, float); + virtual SPIRVValue *addIntegerConstant(SPIRVTypeInt *, uint64_t); + virtual SPIRVValue *addNullConstant(SPIRVType *); + virtual SPIRVValue *addUndef(SPIRVType *TheType); + virtual SPIRVValue *addSamplerConstant(SPIRVType *TheType, SPIRVWord AddrMode, + SPIRVWord ParametricMode, SPIRVWord FilterMode); + virtual SPIRVValue* addPipeStorageConstant(SPIRVType* TheType, + SPIRVWord PacketSize, SPIRVWord PacketAlign, SPIRVWord Capacity); + + // Instruction creation functions + virtual SPIRVInstruction *addPtrAccessChainInst(SPIRVType *, SPIRVValue *, + std::vector<SPIRVValue *>, SPIRVBasicBlock *, bool); + virtual SPIRVInstruction *addAsyncGroupCopy(SPIRVValue *Scope, + SPIRVValue *Dest, SPIRVValue *Src, SPIRVValue *NumElems, SPIRVValue *Stride, + SPIRVValue *Event, SPIRVBasicBlock *BB); + virtual SPIRVInstruction *addExtInst(SPIRVType *, + SPIRVWord, SPIRVWord, const std::vector<SPIRVWord> &, + SPIRVBasicBlock *); + virtual SPIRVInstruction *addExtInst(SPIRVType *, + SPIRVWord, SPIRVWord, const std::vector<SPIRVValue *> &, + SPIRVBasicBlock *); + virtual SPIRVInstruction *addBinaryInst(Op, SPIRVType *, SPIRVValue *, + SPIRVValue *, SPIRVBasicBlock *); + virtual SPIRVInstruction *addCallInst(SPIRVFunction*, + const std::vector<SPIRVWord> &, SPIRVBasicBlock *); + virtual SPIRVInstruction *addCmpInst(Op, SPIRVType *, SPIRVValue *, + SPIRVValue *, SPIRVBasicBlock *); + virtual SPIRVInstruction *addLoadInst(SPIRVValue *, + const std::vector<SPIRVWord>&, SPIRVBasicBlock *); + virtual SPIRVInstruction *addPhiInst(SPIRVType *, std::vector<SPIRVValue *>, + SPIRVBasicBlock *); + virtual SPIRVInstruction *addCompositeConstructInst(SPIRVType *, + const std::vector<SPIRVId>&, SPIRVBasicBlock *); + virtual SPIRVInstruction *addCompositeExtractInst(SPIRVType *, SPIRVValue *, + const std::vector<SPIRVWord>&, SPIRVBasicBlock *); + virtual SPIRVInstruction *addCompositeInsertInst(SPIRVValue *Object, + SPIRVValue *Composite, const std::vector<SPIRVWord>& Indices, + SPIRVBasicBlock *BB); + virtual SPIRVInstruction *addCopyObjectInst(SPIRVType *TheType, + SPIRVValue *Operand, SPIRVBasicBlock *BB); + virtual SPIRVInstruction *addCopyMemoryInst(SPIRVValue *, SPIRVValue *, + const std::vector<SPIRVWord>&, SPIRVBasicBlock *); + virtual SPIRVInstruction *addCopyMemorySizedInst(SPIRVValue *, SPIRVValue *, + SPIRVValue *, const std::vector<SPIRVWord>&, SPIRVBasicBlock *); + virtual SPIRVInstruction *addControlBarrierInst( + SPIRVValue *ExecKind, SPIRVValue *MemKind, + SPIRVValue *MemSema, SPIRVBasicBlock *BB); + virtual SPIRVInstruction *addGroupInst(Op OpCode, SPIRVType *Type, + Scope Scope, const std::vector<SPIRVValue *> &Ops, + SPIRVBasicBlock *BB); + virtual SPIRVInstruction *addInstruction(SPIRVInstruction *Inst, + SPIRVBasicBlock *BB); + virtual SPIRVInstTemplateBase *addInstTemplate(Op OC, + SPIRVBasicBlock* BB, SPIRVType *Ty); + virtual SPIRVInstTemplateBase *addInstTemplate(Op OC, + const std::vector<SPIRVWord>& Ops, SPIRVBasicBlock* BB, SPIRVType *Ty); + virtual SPIRVInstruction *addLifetimeInst(Op OC, SPIRVValue *Object, + SPIRVWord Size, SPIRVBasicBlock *BB); + virtual SPIRVInstruction *addMemoryBarrierInst( + Scope ScopeKind, SPIRVWord MemFlag, SPIRVBasicBlock *BB); + virtual SPIRVInstruction *addUnreachableInst(SPIRVBasicBlock *); + virtual SPIRVInstruction *addReturnInst(SPIRVBasicBlock *); + virtual SPIRVInstruction *addReturnValueInst(SPIRVValue *, SPIRVBasicBlock *); + virtual SPIRVInstruction *addSelectInst(SPIRVValue *, SPIRVValue *, SPIRVValue *, + SPIRVBasicBlock *); + virtual SPIRVInstruction *addLoopMergeInst(SPIRVId MergeBlock, + SPIRVId ContinueTarget, SPIRVWord LoopControl, SPIRVBasicBlock *BB); + virtual SPIRVInstruction *addSelectionMergeInst(SPIRVId MergeBlock, + SPIRVWord SelectionControl, SPIRVBasicBlock *BB); + virtual SPIRVInstruction *addStoreInst(SPIRVValue *, SPIRVValue *, + const std::vector<SPIRVWord>&, SPIRVBasicBlock *); + virtual SPIRVInstruction *addSwitchInst(SPIRVValue *, SPIRVBasicBlock *, + const std::vector<std::pair<std::vector<SPIRVWord>, SPIRVBasicBlock *>>&, + SPIRVBasicBlock *); + virtual SPIRVInstruction *addFModInst(SPIRVType *TheType, SPIRVId TheDividend, + SPIRVId TheDivisor, SPIRVBasicBlock *BB); + virtual SPIRVInstruction *addVectorTimesScalarInst(SPIRVType *TheType, + SPIRVId TheVector, SPIRVId TheScalar, SPIRVBasicBlock *BB); + virtual SPIRVInstruction *addUnaryInst(Op, SPIRVType *, SPIRVValue *, + SPIRVBasicBlock *); + virtual SPIRVInstruction *addVariable(SPIRVType *, bool, SPIRVLinkageTypeKind, + SPIRVValue *, const std::string &, SPIRVStorageClassKind, SPIRVBasicBlock *); + virtual SPIRVValue *addVectorShuffleInst(SPIRVType *Type, SPIRVValue *Vec1, + SPIRVValue *Vec2, const std::vector<SPIRVWord> &Components, + SPIRVBasicBlock *BB); + virtual SPIRVInstruction *addVectorExtractDynamicInst(SPIRVValue *, + SPIRVValue *, SPIRVBasicBlock *); + virtual SPIRVInstruction *addVectorInsertDynamicInst(SPIRVValue *, + SPIRVValue *, SPIRVValue*, SPIRVBasicBlock *); + + // I/O functions + friend spv_ostream & operator<<(spv_ostream &O, SPIRVModule& M); + friend std::istream & operator>>(std::istream &I, SPIRVModule& M); + +private: + SPIRVErrorLog ErrLog; + SPIRVId NextId; + SPIRVTypeInt *BoolType; + SPIRVWord SPIRVVersion; + unsigned short GeneratorId; + unsigned short GeneratorVer; + SPIRVInstructionSchemaKind InstSchema; + SourceLanguage SrcLang; + SPIRVWord SrcLangVer; + std::set<std::string> SrcExtension; + std::set<std::string> SPIRVExt; + SPIRVAddressingModelKind AddrModel; + SPIRVMemoryModelKind MemoryModel; + + typedef std::map<SPIRVId, SPIRVEntry *> SPIRVIdToEntryMap; + typedef std::set<SPIRVEntry *> SPIRVEntrySet; + typedef std::set<SPIRVId> SPIRVIdSet; + typedef std::vector<SPIRVId> SPIRVIdVec; + typedef std::vector<SPIRVFunction *> SPIRVFunctionVector; + typedef std::vector<SPIRVTypeForwardPointer *> SPIRVForwardPointerVec; + typedef std::vector<SPIRVType *> SPIRVTypeVec; + typedef std::vector<SPIRVValue *> SPIRVConstantVector; + typedef std::vector<SPIRVVariable *> SPIRVVariableVec; + typedef std::vector<SPIRVString *> SPIRVStringVec; + typedef std::vector<SPIRVMemberName *> SPIRVMemberNameVec; + typedef std::vector<SPIRVDecorationGroup *> SPIRVDecGroupVec; + typedef std::vector<SPIRVGroupDecorateGeneric *> SPIRVGroupDecVec; + typedef std::map<SPIRVId, SPIRVExtInstSetKind> SPIRVIdToBuiltinSetMap; + typedef std::map<SPIRVExecutionModelKind, SPIRVIdSet> SPIRVExecModelIdSetMap; + typedef std::map<SPIRVExecutionModelKind, SPIRVIdVec> SPIRVExecModelIdVecMap; + typedef std::unordered_map<std::string, SPIRVString*> SPIRVStringMap; + typedef std::map<SPIRVTypeStruct *, std::vector<std::pair<unsigned, SPIRVId>>> + SPIRVUnknownStructFieldMap; + + SPIRVForwardPointerVec ForwardPointerVec; + SPIRVTypeVec TypeVec; + SPIRVIdToEntryMap IdEntryMap; + SPIRVFunctionVector FuncVec; + SPIRVConstantVector ConstVec; + SPIRVVariableVec VariableVec; + SPIRVEntrySet EntryNoId; // Entries without id + SPIRVIdToBuiltinSetMap IdBuiltinMap; + SPIRVIdSet NamedId; + SPIRVStringVec StringVec; + SPIRVMemberNameVec MemberNameVec; + std::shared_ptr<const SPIRVLine> CurrentLine; + SPIRVDecorateSet DecorateSet; + SPIRVDecGroupVec DecGroupVec; + SPIRVGroupDecVec GroupDecVec; + SPIRVExecModelIdSetMap EntryPointSet; + SPIRVExecModelIdVecMap EntryPointVec; + SPIRVStringMap StrMap; + SPIRVCapMap CapMap; + SPIRVUnknownStructFieldMap UnknownStructFieldMap; + std::map<unsigned, SPIRVTypeInt*> IntTypeMap; + std::map<unsigned, SPIRVConstant*> LiteralMap; + + void layoutEntry(SPIRVEntry* Entry); +}; + +SPIRVModuleImpl::~SPIRVModuleImpl() { + for (auto I : EntryNoId) + delete I; + + for (auto I : IdEntryMap) + delete I.second; + + for (auto C : CapMap) + delete C.second; +} + +const std::shared_ptr<const SPIRVLine>& +SPIRVModuleImpl::getCurrentLine() const { + return CurrentLine; +} + +void +SPIRVModuleImpl::setCurrentLine(const std::shared_ptr<const SPIRVLine>& Line) { + CurrentLine = Line; +} + +void +SPIRVModuleImpl::addLine(SPIRVEntry* E, SPIRVId FileNameId, + SPIRVWord Line, SPIRVWord Column) { + if (!(CurrentLine && CurrentLine->equals(FileNameId, Line, Column))) + CurrentLine.reset(new SPIRVLine(this, FileNameId, Line, Column)); + assert(E && "invalid entry"); + E->setLine(CurrentLine); +} + +// Creates decoration group and group decorates from decorates shared by +// multiple targets. +void +SPIRVModuleImpl::optimizeDecorates() { + SPIRVDBG(spvdbgs() << "[optimizeDecorates] begin\n"); + for (auto I = DecorateSet.begin(), E = DecorateSet.end(); I != E;) { + auto D = *I; + SPIRVDBG(spvdbgs() << " check " << *D << '\n'); + if (D->getOpCode() == OpMemberDecorate) { + ++I; + continue; + } + auto ER = DecorateSet.equal_range(D); + SPIRVDBG(spvdbgs() << " equal range " << **ER.first + << " to "; + if (ER.second != DecorateSet.end()) + spvdbgs() << **ER.second; + else + spvdbgs() << "end"; + spvdbgs() << '\n'); + if (std::distance(ER.first, ER.second) < 2) { + I = ER.second; + SPIRVDBG(spvdbgs() << " skip equal range \n"); + continue; + } + SPIRVDBG(spvdbgs() << " add deco group. erase equal range\n"); + auto G = add(new SPIRVDecorationGroup(this, getId())); + std::vector<SPIRVId> Targets; + Targets.push_back(D->getTargetId()); + const_cast<SPIRVDecorateGeneric*>(D)->setTargetId(G->getId()); + G->getDecorations().insert(D); + for (I = ER.first; I != ER.second; ++I) { + auto E = *I; + if (*E == *D) + continue; + Targets.push_back(E->getTargetId()); + } + + // WordCount is only 16 bits. We can only have 65535 - FixedWC targtets per + // group. + // For now, just skip using a group if the number of targets to too big + if (Targets.size() < 65530) { + DecorateSet.erase(ER.first, ER.second); + auto GD = add(new SPIRVGroupDecorate(G, Targets)); + DecGroupVec.push_back(G); + GroupDecVec.push_back(GD); + } + } +} + +SPIRVValue* +SPIRVModuleImpl::addSamplerConstant(SPIRVType* TheType, + SPIRVWord AddrMode, SPIRVWord ParametricMode, SPIRVWord FilterMode) { + return addConstant(new SPIRVConstantSampler(this, TheType, getId(), AddrMode, + ParametricMode, FilterMode)); +} + +SPIRVValue* +SPIRVModuleImpl::addPipeStorageConstant(SPIRVType* TheType, + SPIRVWord PacketSize, SPIRVWord PacketAlign, SPIRVWord Capacity) { + return addConstant(new SPIRVConstantPipeStorage(this, TheType, getId(), + PacketSize, PacketAlign, Capacity)); +} + +void +SPIRVModuleImpl::addCapability(SPIRVCapabilityKind Cap) { + addCapabilities(SPIRV::getCapability(Cap)); + SPIRVDBG(spvdbgs() << "addCapability: " << Cap << '\n'); + if (hasCapability(Cap)) + return; + + CapMap.insert(std::make_pair(Cap, new SPIRVCapability(this, Cap))); +} + +void +SPIRVModuleImpl::addCapabilityInternal(SPIRVCapabilityKind Cap) { + if (AutoAddCapability) { + if (hasCapability(Cap)) + return; + + CapMap.insert(std::make_pair(Cap, new SPIRVCapability(this, Cap))); + } +} + +SPIRVConstant* +SPIRVModuleImpl::getLiteralAsConstant(unsigned Literal) { + auto Loc = LiteralMap.find(Literal); + if (Loc != LiteralMap.end()) + return Loc->second; + auto Ty = addIntegerType(32); + auto V = new SPIRVConstant(this, Ty, getId(), static_cast<uint64_t>(Literal)); + LiteralMap[Literal] = V; + addConstant(V); + return V; +} + +void +SPIRVModuleImpl::layoutEntry(SPIRVEntry* E) { + auto OC = E->getOpCode(); + switch (OC) { + case OpString: + addTo(StringVec, E); + break; + case OpMemberName: + addTo(MemberNameVec, E); + break; + case OpVariable: { + auto BV = static_cast<SPIRVVariable*>(E); + if (!BV->getParent()) + addTo(VariableVec, E); + } + break; + default: + if (isTypeOpCode(OC)) + TypeVec.push_back(static_cast<SPIRVType*>(E)); + else if (isConstantOpCode(OC)) + ConstVec.push_back(static_cast<SPIRVConstant*>(E)); + break; + } +} + +// Add an entry to the id to entry map. +// Assert if the id is mapped to a different entry. +// Certain entries need to be add to specific collectors to maintain +// logic layout of SPIRV. +SPIRVEntry * +SPIRVModuleImpl::addEntry(SPIRVEntry *Entry) { + assert(Entry && "Invalid entry"); + if (Entry->hasId()) { + SPIRVId Id = Entry->getId(); + assert(Entry->getId() != SPIRVID_INVALID && "Invalid id"); + SPIRVEntry *Mapped = nullptr; + if (exist(Id, &Mapped)) { + if (Mapped->getOpCode() == OpForward) { + replaceForward(static_cast<SPIRVForward *>(Mapped), Entry); + } else { + assert(Mapped == Entry && "Id used twice"); + } + } else + IdEntryMap[Id] = Entry; + } else { + // Entry of OpLine will be deleted by std::shared_ptr automatically. + if (Entry->getOpCode() != OpLine) + EntryNoId.insert(Entry); + } + + Entry->setModule(this); + + layoutEntry(Entry); + if (AutoAddCapability) { + for (auto &I:Entry->getRequiredCapability()) { + addCapability(I); + } + } + if (ValidateCapability) { + assert(none_of( + Entry->getRequiredCapability().begin(), + Entry->getRequiredCapability().end(), + [this](SPIRVCapabilityKind &val) { return !CapMap.count(val); })); + } + return Entry; +} + +bool +SPIRVModuleImpl::exist(SPIRVId Id) const { + return exist(Id, nullptr); +} + +bool +SPIRVModuleImpl::exist(SPIRVId Id, SPIRVEntry **Entry) const { + assert (Id != SPIRVID_INVALID && "Invalid Id"); + SPIRVIdToEntryMap::const_iterator Loc = IdEntryMap.find(Id); + if (Loc == IdEntryMap.end()) + return false; + if (Entry) + *Entry = Loc->second; + return true; +} + +// If Id is invalid, returns the next available id. +// Otherwise returns the given id and adjust the next available id by increment. +SPIRVId +SPIRVModuleImpl::getId(SPIRVId Id, unsigned increment) { + if (!isValidId(Id)) + Id = NextId; + else + NextId = std::max(Id, NextId); + NextId += increment; + return Id; +} + +SPIRVEntry * +SPIRVModuleImpl::getEntry(SPIRVId Id) const { + assert (Id != SPIRVID_INVALID && "Invalid Id"); + SPIRVIdToEntryMap::const_iterator Loc = IdEntryMap.find(Id); + assert (Loc != IdEntryMap.end() && "Id is not in map"); + return Loc->second; +} + +SPIRVExtInstSetKind +SPIRVModuleImpl::getBuiltinSet(SPIRVId SetId) const { + auto Loc = IdBuiltinMap.find(SetId); + assert(Loc != IdBuiltinMap.end() && "Invalid builtin set id"); + return Loc->second; +} + +bool +SPIRVModuleImpl::isEntryPoint(SPIRVExecutionModelKind ExecModel, SPIRVId EP) + const { + assert(isValid(ExecModel) && "Invalid execution model"); + assert(EP != SPIRVID_INVALID && "Invalid function id"); + auto Loc = EntryPointSet.find(ExecModel); + if (Loc == EntryPointSet.end()) + return false; + return Loc->second.count(EP); +} + +// Module change functions +bool +SPIRVModuleImpl::importBuiltinSet(const std::string& BuiltinSetName, + SPIRVId *BuiltinSetId) { + SPIRVId TmpBuiltinSetId = getId(); + if (!importBuiltinSetWithId(BuiltinSetName, TmpBuiltinSetId)) + return false; + if (BuiltinSetId) + *BuiltinSetId = TmpBuiltinSetId; + return true; +} + +bool +SPIRVModuleImpl::importBuiltinSetWithId(const std::string& BuiltinSetName, + SPIRVId BuiltinSetId) { + SPIRVExtInstSetKind BuiltinSet = SPIRVEIS_Count; + SPIRVCKRT(SPIRVBuiltinSetNameMap::rfind(BuiltinSetName, &BuiltinSet), + InvalidBuiltinSetName, "Actual is " + BuiltinSetName); + IdBuiltinMap[BuiltinSetId] = BuiltinSet; + return true; +} + +void +SPIRVModuleImpl::setAlignment(SPIRVValue *V, SPIRVWord A) { + V->setAlignment(A); +} + +void +SPIRVModuleImpl::setName(SPIRVEntry *E, const std::string &Name) { + E->setName(Name); + if (!E->hasId()) + return; + if (!Name.empty()) + NamedId.insert(E->getId()); + else + NamedId.erase(E->getId()); +} + +void SPIRVModuleImpl::resolveUnknownStructFields() { + for (auto &KV : UnknownStructFieldMap) { + auto *Struct = KV.first; + for (auto &Indices : KV.second) { + unsigned I = Indices.first; + SPIRVId ID = Indices.second; + + auto Ty = static_cast<SPIRVType *>(getEntry(ID)); + Struct->setMemberType(I, Ty); + } + } +} + +// Type creation functions +template<class T> +T * +SPIRVModuleImpl::addType(T *Ty) { + add(Ty); + if (!Ty->getName().empty()) + setName(Ty, Ty->getName()); + return Ty; +} + +SPIRVTypeVoid * +SPIRVModuleImpl::addVoidType() { + return addType(new SPIRVTypeVoid(this, getId())); +} + +SPIRVTypeArray * +SPIRVModuleImpl::addArrayType(SPIRVType *ElementType, SPIRVConstant *Length) { + return addType(new SPIRVTypeArray(this, getId(), ElementType, Length)); +} + +SPIRVTypeBool * +SPIRVModuleImpl::addBoolType() { + return addType(new SPIRVTypeBool(this, getId())); +} + +SPIRVTypeInt * +SPIRVModuleImpl::addIntegerType(unsigned BitWidth) { + auto Loc = IntTypeMap.find(BitWidth); + if (Loc != IntTypeMap.end()) + return Loc->second; + auto Ty = new SPIRVTypeInt(this, getId(), BitWidth, false); + IntTypeMap[BitWidth] = Ty; + return addType(Ty); +} + +SPIRVTypeFloat * +SPIRVModuleImpl::addFloatType(unsigned BitWidth) { + SPIRVTypeFloat *T = addType(new SPIRVTypeFloat(this, getId(), BitWidth)); + return T; +} + +SPIRVTypePointer * +SPIRVModuleImpl::addPointerType(SPIRVStorageClassKind StorageClass, + SPIRVType *ElementType) { + return addType(new SPIRVTypePointer(this, getId(), StorageClass, + ElementType)); +} + +SPIRVTypeFunction * +SPIRVModuleImpl::addFunctionType(SPIRVType *ReturnType, + const std::vector<SPIRVType *>& ParameterTypes) { + return addType(new SPIRVTypeFunction(this, getId(), ReturnType, + ParameterTypes)); +} + +SPIRVTypeOpaque* +SPIRVModuleImpl::addOpaqueType(const std::string& Name) { + return addType(new SPIRVTypeOpaque(this, getId(), Name)); +} + +SPIRVTypeStruct *SPIRVModuleImpl::openStructType(unsigned NumMembers, + const std::string &Name) { + auto T = new SPIRVTypeStruct(this, getId(), NumMembers, Name); + return T; +} + +void SPIRVModuleImpl::closeStructType(SPIRVTypeStruct *T, bool Packed) { + addType(T); + T->setPacked(Packed); +} + +SPIRVTypeVector* +SPIRVModuleImpl::addVectorType(SPIRVType* CompType, SPIRVWord CompCount) { + return addType(new SPIRVTypeVector(this, getId(), CompType, CompCount)); +} +SPIRVType * +SPIRVModuleImpl::addOpaqueGenericType(Op TheOpCode) { + return addType(new SPIRVTypeOpaqueGeneric(TheOpCode, this, getId())); +} + +SPIRVTypeDeviceEvent * +SPIRVModuleImpl::addDeviceEventType() { + return addType(new SPIRVTypeDeviceEvent(this, getId())); +} + +SPIRVTypeQueue * +SPIRVModuleImpl::addQueueType() { + return addType(new SPIRVTypeQueue(this, getId())); +} + +SPIRVTypePipe* +SPIRVModuleImpl::addPipeType() { + return addType(new SPIRVTypePipe(this, getId())); +} + +SPIRVTypeImage * +SPIRVModuleImpl::addImageType(SPIRVType *SampledType, + const SPIRVTypeImageDescriptor &Desc) { + return addType(new SPIRVTypeImage(this, getId(), + SampledType ? SampledType->getId() : 0, Desc)); +} + +SPIRVTypeImage * +SPIRVModuleImpl::addImageType(SPIRVType *SampledType, + const SPIRVTypeImageDescriptor &Desc, SPIRVAccessQualifierKind Acc) { + return addType(new SPIRVTypeImage(this, getId(), + SampledType ? SampledType->getId() : 0, Desc, Acc)); +} + +SPIRVTypeSampler * +SPIRVModuleImpl::addSamplerType() { + return addType(new SPIRVTypeSampler(this, getId())); +} + +SPIRVTypePipeStorage* +SPIRVModuleImpl::addPipeStorageType() { + return addType(new SPIRVTypePipeStorage(this, getId())); +} + +SPIRVTypeSampledImage * +SPIRVModuleImpl::addSampledImageType(SPIRVTypeImage *T) { + return addType(new SPIRVTypeSampledImage(this, getId(), T)); +} + +void SPIRVModuleImpl::createForwardPointers() { + std::unordered_set<SPIRVId> Seen; + + for (auto *T : TypeVec) { + if (T->hasId()) + Seen.insert(T->getId()); + + if (!T->isTypeStruct()) + continue; + + auto ST = static_cast<SPIRVTypeStruct *>(T); + + for (unsigned i = 0; i < ST->getStructMemberCount(); ++i) { + auto MemberTy = ST->getStructMemberType(i); + if (!MemberTy->isTypePointer()) continue; + auto Ptr = static_cast<SPIRVTypePointer *>(MemberTy); + + if (Seen.find(Ptr->getId()) == Seen.end()) { + ForwardPointerVec.push_back(new SPIRVTypeForwardPointer( + this, Ptr, Ptr->getPointerStorageClass())); + } + } + } +} + +SPIRVFunction * +SPIRVModuleImpl::addFunction(SPIRVFunction *Func) { + FuncVec.push_back(add(Func)); + return Func; +} + +SPIRVFunction * +SPIRVModuleImpl::addFunction(SPIRVTypeFunction *FuncType, SPIRVId Id) { + return addFunction(new SPIRVFunction(this, FuncType, + getId(Id, FuncType->getNumParameters() + 1))); +} + +SPIRVBasicBlock * +SPIRVModuleImpl::addBasicBlock(SPIRVFunction *Func, SPIRVId Id) { + return Func->addBasicBlock(new SPIRVBasicBlock(getId(Id), Func)); +} + +const SPIRVDecorateGeneric * +SPIRVModuleImpl::addDecorate(SPIRVDecorateGeneric *Dec) { + add(Dec); + SPIRVId Id = Dec->getTargetId(); + bool Found = exist(Id); (void)Found; - assert (Found && "Decorate target does not exist");
- if (!Dec->getOwner())
- DecorateSet.insert(Dec);
- addCapabilities(Dec->getRequiredCapability());
- return Dec;
-}
-
-void
-SPIRVModuleImpl::addEntryPoint(SPIRVExecutionModelKind ExecModel,
- SPIRVId EntryPoint){
- assert(isValid(ExecModel) && "Invalid execution model");
- assert(EntryPoint != SPIRVID_INVALID && "Invalid entry point");
- EntryPointSet[ExecModel].insert(EntryPoint);
- EntryPointVec[ExecModel].push_back(EntryPoint);
- addCapabilities(SPIRV::getCapability(ExecModel));
-}
-
-SPIRVForward *
-SPIRVModuleImpl::addForward(SPIRVType *Ty) {
- return add(new SPIRVForward(this, Ty, getId()));
-}
-
-SPIRVForward *
-SPIRVModuleImpl::addForward(SPIRVId Id, SPIRVType *Ty) {
- return add(new SPIRVForward(this, Ty, Id));
-}
-
-SPIRVEntry *
-SPIRVModuleImpl::replaceForward(SPIRVForward *Forward, SPIRVEntry *Entry) {
- SPIRVId Id = Entry->getId();
- SPIRVId ForwardId = Forward->getId();
- if (ForwardId == Id)
- IdEntryMap[Id] = Entry;
- else {
- auto Loc = IdEntryMap.find(Id);
- assert(Loc != IdEntryMap.end());
- IdEntryMap.erase(Loc);
- Entry->setId(ForwardId);
- IdEntryMap[ForwardId] = Entry;
- }
- // Annotations include name, decorations, execution modes
- Entry->takeAnnotations(Forward);
- delete Forward;
- return Entry;
-}
-
-void
-SPIRVModuleImpl::eraseInstruction(SPIRVInstruction *I, SPIRVBasicBlock *BB) {
- SPIRVId Id = I->getId();
- BB->eraseInstruction(I);
- auto Loc = IdEntryMap.find(Id);
- assert(Loc != IdEntryMap.end());
- IdEntryMap.erase(Loc);
- delete I;
-}
-
-SPIRVValue *
-SPIRVModuleImpl::addConstant(SPIRVValue *C) {
- return add(C);
-}
-
-SPIRVValue *
-SPIRVModuleImpl::addConstant(SPIRVType *Ty, uint64_t V) {
- if (Ty->isTypeBool()) {
- if (V)
- return addConstant(new SPIRVConstantTrue(this, Ty, getId()));
- else
- return addConstant(new SPIRVConstantFalse(this, Ty, getId()));
- }
- if (Ty->isTypeInt())
- return addIntegerConstant(static_cast<SPIRVTypeInt*>(Ty), V);
- return addConstant(new SPIRVConstant(this, Ty, getId(), V));
-}
-
-SPIRVValue *
-SPIRVModuleImpl::addIntegerConstant(SPIRVTypeInt *Ty, uint64_t V) {
- if (Ty->getBitWidth() == 32) {
+ assert (Found && "Decorate target does not exist"); + if (!Dec->getOwner()) + DecorateSet.insert(Dec); + addCapabilities(Dec->getRequiredCapability()); + return Dec; +} + +void +SPIRVModuleImpl::addEntryPoint(SPIRVExecutionModelKind ExecModel, + SPIRVId EntryPoint){ + assert(isValid(ExecModel) && "Invalid execution model"); + assert(EntryPoint != SPIRVID_INVALID && "Invalid entry point"); + EntryPointSet[ExecModel].insert(EntryPoint); + EntryPointVec[ExecModel].push_back(EntryPoint); + addCapabilities(SPIRV::getCapability(ExecModel)); +} + +SPIRVForward * +SPIRVModuleImpl::addForward(SPIRVType *Ty) { + return add(new SPIRVForward(this, Ty, getId())); +} + +SPIRVForward * +SPIRVModuleImpl::addForward(SPIRVId Id, SPIRVType *Ty) { + return add(new SPIRVForward(this, Ty, Id)); +} + +SPIRVEntry * +SPIRVModuleImpl::replaceForward(SPIRVForward *Forward, SPIRVEntry *Entry) { + SPIRVId Id = Entry->getId(); + SPIRVId ForwardId = Forward->getId(); + if (ForwardId == Id) + IdEntryMap[Id] = Entry; + else { + auto Loc = IdEntryMap.find(Id); + assert(Loc != IdEntryMap.end()); + IdEntryMap.erase(Loc); + Entry->setId(ForwardId); + IdEntryMap[ForwardId] = Entry; + } + // Annotations include name, decorations, execution modes + Entry->takeAnnotations(Forward); + delete Forward; + return Entry; +} + +void +SPIRVModuleImpl::eraseInstruction(SPIRVInstruction *I, SPIRVBasicBlock *BB) { + SPIRVId Id = I->getId(); + BB->eraseInstruction(I); + auto Loc = IdEntryMap.find(Id); + assert(Loc != IdEntryMap.end()); + IdEntryMap.erase(Loc); + delete I; +} + +SPIRVValue * +SPIRVModuleImpl::addConstant(SPIRVValue *C) { + return add(C); +} + +SPIRVValue * +SPIRVModuleImpl::addConstant(SPIRVType *Ty, uint64_t V) { + if (Ty->isTypeBool()) { + if (V) + return addConstant(new SPIRVConstantTrue(this, Ty, getId())); + else + return addConstant(new SPIRVConstantFalse(this, Ty, getId())); + } + if (Ty->isTypeInt()) + return addIntegerConstant(static_cast<SPIRVTypeInt*>(Ty), V); + return addConstant(new SPIRVConstant(this, Ty, getId(), V)); +} + +SPIRVValue * +SPIRVModuleImpl::addIntegerConstant(SPIRVTypeInt *Ty, uint64_t V) { + if (Ty->getBitWidth() == 32) { unsigned I32 = static_cast<unsigned>(V); - assert(I32 == V && "Integer value truncated");
- return getLiteralAsConstant(I32);
- }
- return addConstant(new SPIRVConstant(this, Ty, getId(), V));
-}
-
-SPIRVValue *
-SPIRVModuleImpl::addFloatConstant(SPIRVTypeFloat *Ty, float V) {
- return addConstant(new SPIRVConstant(this, Ty, getId(), V));
-}
-
-SPIRVValue *
-SPIRVModuleImpl::addDoubleConstant(SPIRVTypeFloat *Ty, double V) {
- return addConstant(new SPIRVConstant(this, Ty, getId(), V));
-}
-
-SPIRVValue *
-SPIRVModuleImpl::addNullConstant(SPIRVType *Ty) {
- return addConstant(new SPIRVConstantNull(this, Ty, getId()));
-}
-
-SPIRVValue *
-SPIRVModuleImpl::addCompositeConstant(SPIRVType *Ty,
- const std::vector<SPIRVValue*>& Elements) {
- return addConstant(new SPIRVConstantComposite(this, Ty, getId(), Elements));
-}
-
-SPIRVValue *
-SPIRVModuleImpl::addUndef(SPIRVType *TheType) {
- return addConstant(new SPIRVUndef(this, TheType, getId()));
-}
-
-// Instruction creation functions
-
-SPIRVInstruction *
-SPIRVModuleImpl::addStoreInst(SPIRVValue *Target, SPIRVValue *Source,
- const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *BB) {
- return BB->addInstruction(new SPIRVStore(Target->getId(),
- Source->getId(), TheMemoryAccess, BB));
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addSwitchInst(SPIRVValue *Select, SPIRVBasicBlock *Default,
- const std::vector<std::pair<std::vector<SPIRVWord>, SPIRVBasicBlock *>>& Pairs,
- SPIRVBasicBlock *BB) {
- return BB->addInstruction(new SPIRVSwitch(Select, Default, Pairs, BB));
-}
-SPIRVInstruction *
-SPIRVModuleImpl::addFModInst(SPIRVType *TheType, SPIRVId TheDividend,
- SPIRVId TheDivisor, SPIRVBasicBlock *BB) {
- return BB->addInstruction(new SPIRVFMod(TheType, getId(), TheDividend,
- TheDivisor, BB));
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addVectorTimesScalarInst(SPIRVType *TheType, SPIRVId TheVector,
- SPIRVId TheScalar, SPIRVBasicBlock *BB) {
- return BB->addInstruction(new SPIRVVectorTimesScalar(TheType, getId(),
- TheVector, TheScalar, BB));
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addGroupInst(Op OpCode, SPIRVType *Type,
- Scope Scope, const std::vector<SPIRVValue *> &Ops,
- SPIRVBasicBlock *BB) {
- assert(!Type || !Type->isTypeVoid());
- auto WordOps = getIds(Ops);
- WordOps.insert(WordOps.begin(), Scope);
- return addInstTemplate(OpCode, WordOps, BB, Type);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addInstruction(SPIRVInstruction *Inst, SPIRVBasicBlock *BB) {
- if (BB)
- return BB->addInstruction(Inst);
- if (Inst->getOpCode() != OpSpecConstantOp)
- Inst = createSpecConstantOpInst(Inst);
- return static_cast<SPIRVInstruction *>(addConstant(Inst));
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addLoadInst(SPIRVValue *Source,
- const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVLoad(getId(), Source->getId(),
- TheMemoryAccess, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addPhiInst(SPIRVType *Type,
- std::vector<SPIRVValue *> IncomingPairs, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVPhi(Type, getId(), IncomingPairs, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addExtInst(SPIRVType *TheType, SPIRVWord BuiltinSet,
- SPIRVWord EntryPoint, const std::vector<SPIRVWord> &Args,
- SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVExtInst(TheType, getId(),
- BuiltinSet, EntryPoint, Args, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addExtInst(SPIRVType *TheType, SPIRVWord BuiltinSet,
- SPIRVWord EntryPoint, const std::vector<SPIRVValue *> &Args,
- SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVExtInst(TheType, getId(),
- BuiltinSet, EntryPoint, Args, BB), BB);
-}
-
-SPIRVInstruction*
-SPIRVModuleImpl::addCallInst(SPIRVFunction* TheFunction,
- const std::vector<SPIRVWord> &TheArguments, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVFunctionCall(getId(), TheFunction,
- TheArguments, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addBinaryInst(Op TheOpCode, SPIRVType *Type,
- SPIRVValue *Op1, SPIRVValue *Op2, SPIRVBasicBlock *BB){
- return addInstruction(SPIRVInstTemplateBase::create(TheOpCode, Type, getId(),
- getVec(Op1->getId(), Op2->getId()), BB, this), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addUnreachableInst(SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVUnreachable(BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addReturnInst(SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVReturn(BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addReturnValueInst(SPIRVValue *ReturnValue, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVReturnValue(ReturnValue, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addUnaryInst(Op TheOpCode, SPIRVType *TheType,
- SPIRVValue *Op, SPIRVBasicBlock *BB) {
- return addInstruction(SPIRVInstTemplateBase::create(TheOpCode,
- TheType, getId(), getVec(Op->getId()), BB, this), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addVectorExtractDynamicInst(SPIRVValue *TheVector,
- SPIRVValue *Index, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVVectorExtractDynamic(getId(), TheVector,
- Index, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addVectorInsertDynamicInst(SPIRVValue *TheVector,
-SPIRVValue *TheComponent, SPIRVValue*Index, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVVectorInsertDynamic(getId(), TheVector,
- TheComponent, Index, BB), BB);
-}
-
-SPIRVValue *
-SPIRVModuleImpl::addVectorShuffleInst(SPIRVType * Type, SPIRVValue *Vec1,
- SPIRVValue *Vec2, const std::vector<SPIRVWord> &Components,
- SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVVectorShuffle(getId(), Type, Vec1, Vec2,
- Components, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addBranchInst(SPIRVLabel *TargetLabel, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVBranch(TargetLabel, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addBranchConditionalInst(SPIRVValue *Condition,
- SPIRVLabel *TrueLabel, SPIRVLabel *FalseLabel, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVBranchConditional(Condition, TrueLabel,
- FalseLabel, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addCmpInst(Op TheOpCode, SPIRVType *TheType,
- SPIRVValue *Op1, SPIRVValue *Op2, SPIRVBasicBlock *BB) {
- return addInstruction(SPIRVInstTemplateBase::create(TheOpCode,
- TheType, getId(), getVec(Op1->getId(), Op2->getId()), BB, this), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addControlBarrierInst(SPIRVValue *ExecKind,
- SPIRVValue *MemKind, SPIRVValue *MemSema, SPIRVBasicBlock *BB) {
- return addInstruction(
- new SPIRVControlBarrier(ExecKind, MemKind, MemSema, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addLifetimeInst(Op OC, SPIRVValue *Object, SPIRVWord Size,
- SPIRVBasicBlock *BB) {
- if(OC == OpLifetimeStart)
- return BB->addInstruction(new SPIRVLifetimeStart(Object->getId(),
- Size, BB));
- else
- return BB->addInstruction(new SPIRVLifetimeStop(Object->getId(),
- Size, BB));
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addMemoryBarrierInst(Scope ScopeKind,
- SPIRVWord MemFlag, SPIRVBasicBlock *BB) {
- return addInstruction(SPIRVInstTemplateBase::create(OpMemoryBarrier,
- nullptr, SPIRVID_INVALID,
- getVec(static_cast<SPIRVWord>(ScopeKind), MemFlag), BB, this), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addSelectInst(SPIRVValue *Condition, SPIRVValue *Op1,
- SPIRVValue *Op2, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVSelect(getId(), Condition->getId(),
- Op1->getId(), Op2->getId(), BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addSelectionMergeInst(SPIRVId MergeBlock,
- SPIRVWord SelectionControl, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVSelectionMerge(MergeBlock, SelectionControl, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addLoopMergeInst(SPIRVId MergeBlock, SPIRVId ContinueTarget,
- SPIRVWord LoopControl, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVLoopMerge(MergeBlock, ContinueTarget,
- LoopControl, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addPtrAccessChainInst(SPIRVType *Type, SPIRVValue *Base,
- std::vector<SPIRVValue *> Indices, SPIRVBasicBlock *BB, bool IsInBounds){
- return addInstruction(SPIRVInstTemplateBase::create(
- IsInBounds?OpInBoundsPtrAccessChain:OpPtrAccessChain,
- Type, getId(), getVec(Base->getId(), Base->getIds(Indices)),
- BB, this), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addAsyncGroupCopy(SPIRVValue *Scope,
- SPIRVValue *Dest, SPIRVValue *Src, SPIRVValue *NumElems, SPIRVValue *Stride,
- SPIRVValue *Event, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVGroupAsyncCopy(Scope, getId(), Dest, Src,
- NumElems, Stride, Event, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addCompositeConstructInst(SPIRVType *Type,
- const std::vector<SPIRVId>& Constituents, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVCompositeConstruct(Type, getId(),
- Constituents, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addCompositeExtractInst(SPIRVType *Type, SPIRVValue *TheVector,
- const std::vector<SPIRVWord>& Indices, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVCompositeExtract(Type, getId(), TheVector,
- Indices, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addCompositeInsertInst(SPIRVValue *Object,
- SPIRVValue *Composite, const std::vector<SPIRVWord>& Indices,
- SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVCompositeInsert(getId(), Object, Composite,
- Indices, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addCopyObjectInst(SPIRVType *TheType, SPIRVValue *Operand,
- SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVCopyObject(TheType, getId(), Operand, BB), BB);
-
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addCopyMemoryInst(SPIRVValue *TheTarget, SPIRVValue *TheSource,
- const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVCopyMemory(TheTarget, TheSource,
- TheMemoryAccess, BB), BB);
-}
-
-SPIRVInstruction *
-SPIRVModuleImpl::addCopyMemorySizedInst(SPIRVValue *TheTarget,
- SPIRVValue *TheSource, SPIRVValue *TheSize,
- const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *BB) {
- return addInstruction(new SPIRVCopyMemorySized(TheTarget, TheSource, TheSize,
- TheMemoryAccess, BB), BB);
-}
-
-SPIRVInstruction*
-SPIRVModuleImpl::addVariable(SPIRVType *Type, bool IsConstant,
- SPIRVLinkageTypeKind LinkageType, SPIRVValue *Initializer,
- const std::string &Name, SPIRVStorageClassKind StorageClass,
- SPIRVBasicBlock *BB) {
- SPIRVVariable *Variable = new SPIRVVariable(Type, getId(), Initializer,
- Name, StorageClass, BB, this);
- if (BB)
- return addInstruction(Variable, BB);
-
- add(Variable);
- if (LinkageType != LinkageTypeInternal)
- Variable->setLinkageType(LinkageType);
- Variable->setIsConstant(IsConstant);
- return Variable;
-}
-
-template<class T>
-spv_ostream &
-operator<< (spv_ostream &O, const std::vector<T *>& V) {
- for (auto &I: V)
- O << *I;
- return O;
-}
-
-template<class T, class B>
-spv_ostream &
-operator<< (spv_ostream &O, const std::multiset<T *, B>& V) {
- for (auto &I: V)
- O << *I;
- return O;
-}
-
-// To satisfy SPIR-V spec requirement:
-// "All operands must be declared before being used",
-// we do DFS based topological sort
-// https://en.wikipedia.org/wiki/Topological_sorting#Depth-first_search
-class TopologicalSort {
- enum DFSState : char {
- Unvisited,
- Discovered,
- Visited
- };
- typedef std::vector<SPIRVType *> SPIRVTypeVec;
- typedef std::vector<SPIRVValue *> SPIRVConstantVector;
- typedef std::vector<SPIRVVariable *> SPIRVVariableVec;
- typedef std::vector<SPIRVEntry *> SPIRVConstAndVarVec;
- typedef std::vector<SPIRVTypeForwardPointer *> SPIRVForwardPointerVec;
- typedef std::function<bool(SPIRVEntry*, SPIRVEntry*)> IdComp;
- typedef std::map<SPIRVEntry*, DFSState, IdComp> EntryStateMapTy;
-
- SPIRVTypeVec TypeIntVec;
- SPIRVConstantVector ConstIntVec;
- SPIRVTypeVec TypeVec;
- SPIRVConstAndVarVec ConstAndVarVec;
- const SPIRVForwardPointerVec& ForwardPointerVec;
- EntryStateMapTy EntryStateMap;
-
- friend spv_ostream & operator<<(spv_ostream &O, const TopologicalSort &S);
-
-// This method implements recursive depth-first search among all Entries in
-// EntryStateMap. Traversing entries and adding them to corresponding container
-// after visiting all dependent entries(post-order traversal) guarantees that
-// the entry's operands will appear in the container before the entry itslef.
- void visit(SPIRVEntry* E) {
- DFSState& State = EntryStateMap[E];
- assert(State != Discovered && "Cyclic dependency detected");
- if (State == Visited)
- return;
- State = Discovered;
- for (SPIRVEntry *Op : E->getNonLiteralOperands()) {
- auto Comp = [&Op](SPIRVTypeForwardPointer *FwdPtr) {
- return FwdPtr->getPointer() == Op;
- };
- // Skip forward referenced pointers
- if (Op->getOpCode() == OpTypePointer &&
- find_if(ForwardPointerVec.begin(), ForwardPointerVec.end(), Comp) !=
- ForwardPointerVec.end())
- continue;
- visit(Op);
- }
- State = Visited;
- Op OC = E->getOpCode();
- if (OC == OpTypeInt)
- TypeIntVec.push_back(static_cast<SPIRVType*>(E));
- else if (isConstantOpCode(OC)) {
- SPIRVConstant *C = static_cast<SPIRVConstant*>(E);
- if (C->getType()->isTypeInt())
- ConstIntVec.push_back(C);
- else
- ConstAndVarVec.push_back(E);
- } else if (isTypeOpCode(OC))
- TypeVec.push_back(static_cast<SPIRVType*>(E));
- else
- ConstAndVarVec.push_back(E);
- }
-public:
- TopologicalSort(const SPIRVTypeVec &_TypeVec,
- const SPIRVConstantVector &_ConstVec,
- const SPIRVVariableVec &_VariableVec,
- const SPIRVForwardPointerVec &_ForwardPointerVec) :
- ForwardPointerVec(_ForwardPointerVec),
- EntryStateMap([](SPIRVEntry* a, SPIRVEntry* b) -> bool {
- return a->getId() < b->getId();
- })
- {
- // Collect entries for sorting
- for (auto *T : _TypeVec)
- EntryStateMap[T] = DFSState::Unvisited;
- for (auto *C : _ConstVec)
- EntryStateMap[C] = DFSState::Unvisited;
- for (auto *V : _VariableVec)
- EntryStateMap[V] = DFSState::Unvisited;
- // Run topoligical sort
- for (auto ES : EntryStateMap)
- visit(ES.first);
- }
-};
-
-spv_ostream &
-operator<< (spv_ostream &O, const TopologicalSort &S) {
- O << S.TypeIntVec
- << S.ConstIntVec
- << S.TypeVec
- << S.ConstAndVarVec;
- return O;
-}
-
-spv_ostream &
-operator<< (spv_ostream &O, SPIRVModule &M) {
- SPIRVModuleImpl &MI = *static_cast<SPIRVModuleImpl*>(&M);
-
- SPIRVEncoder Encoder(O);
- Encoder << MagicNumber
- << MI.SPIRVVersion
- << (((SPIRVWord)MI.GeneratorId << 16) | MI.GeneratorVer)
- << MI.NextId /* Bound for Id */
- << MI.InstSchema;
- O << SPIRVNL();
-
- for (auto &I:MI.CapMap)
- O << *I.second;
-
- for (auto &I:M.getExtension()) {
- assert(!I.empty() && "Invalid extension");
- O << SPIRVExtension(&M, I);
- }
-
- for (auto &I:MI.IdBuiltinMap)
- O << SPIRVExtInstImport(&M, I.first, SPIRVBuiltinSetNameMap::map(I.second));
-
- O << SPIRVMemoryModel(&M);
-
- for (auto &I:MI.EntryPointVec)
- for (auto &II:I.second)
- O << SPIRVEntryPoint(&M, I.first, II,
- M.get<SPIRVFunction>(II)->getName());
-
- for (auto &I:MI.EntryPointVec)
- for (auto &II:I.second)
- MI.get<SPIRVFunction>(II)->encodeExecutionModes(O);
-
- O << MI.StringVec;
-
- for (auto &I:M.getSourceExtension()) {
- assert(!I.empty() && "Invalid source extension");
- O << SPIRVSourceExtension(&M, I);
- }
-
- O << SPIRVSource(&M);
-
- for (auto &I:MI.NamedId) {
- // Don't output name for entry point since it is redundant
- bool IsEntryPoint = false;
- for (auto &EPS:MI.EntryPointSet)
- if (EPS.second.count(I)) {
- IsEntryPoint = true;
- break;
- }
- if (!IsEntryPoint)
- M.getEntry(I)->encodeName(O);
- }
-
- O << MI.MemberNameVec
- << MI.DecGroupVec
- << MI.DecorateSet
- << MI.GroupDecVec
- << MI.ForwardPointerVec
- << TopologicalSort(MI.TypeVec, MI.ConstVec, MI.VariableVec,
- MI.ForwardPointerVec)
- << SPIRVNL()
- << MI.FuncVec;
- return O;
-}
-
-template<class T>
-void SPIRVModuleImpl::addTo(std::vector<T*>& V, SPIRVEntry* E) {
- V.push_back(static_cast<T *>(E));
-}
-
-// The first decoration group includes all the previously defined decorates.
-// The second decoration group includes all the decorates defined between the
-// first and second decoration group. So long so forth.
-SPIRVDecorationGroup*
-SPIRVModuleImpl::addDecorationGroup() {
- return addDecorationGroup(new SPIRVDecorationGroup(this, getId()));
-}
-
-SPIRVDecorationGroup*
-SPIRVModuleImpl::addDecorationGroup(SPIRVDecorationGroup* Group) {
- add(Group);
- Group->takeDecorates(DecorateSet);
- DecGroupVec.push_back(Group);
- SPIRVDBG(spvdbgs() << "[addDecorationGroup] {" << *Group << "}\n";
- spvdbgs() << " Remaining DecorateSet: {" << DecorateSet << "}\n");
- assert(DecorateSet.empty());
- return Group;
-}
-
-SPIRVGroupDecorateGeneric*
-SPIRVModuleImpl::addGroupDecorateGeneric(SPIRVGroupDecorateGeneric *GDec) {
- add(GDec);
- GDec->decorateTargets();
- GroupDecVec.push_back(GDec);
- return GDec;
-}
-SPIRVGroupDecorate*
-SPIRVModuleImpl::addGroupDecorate(
- SPIRVDecorationGroup* Group, const std::vector<SPIRVEntry*>& Targets) {
- auto GD = new SPIRVGroupDecorate(Group, getIds(Targets));
- addGroupDecorateGeneric(GD);
- return GD;
-}
-
-SPIRVGroupMemberDecorate*
-SPIRVModuleImpl::addGroupMemberDecorate(
- SPIRVDecorationGroup* Group, const std::vector<SPIRVEntry*>& Targets) {
- auto GMD = new SPIRVGroupMemberDecorate(Group, getIds(Targets));
- addGroupDecorateGeneric(GMD);
- return GMD;
-}
-
-SPIRVString*
-SPIRVModuleImpl::getString(const std::string& Str) {
- auto Loc = StrMap.find(Str);
- if (Loc != StrMap.end())
- return Loc->second;
- auto S = add(new SPIRVString(this, getId(), Str));
- StrMap[Str] = S;
- return S;
-}
-
-SPIRVMemberName*
-SPIRVModuleImpl::addMemberName(SPIRVTypeStruct* ST,
- SPIRVWord MemberNumber, const std::string& Name) {
- return add(new SPIRVMemberName(ST, MemberNumber, Name));
-}
-
-void SPIRVModuleImpl::addUnknownStructField(SPIRVTypeStruct *Struct, unsigned I,
- SPIRVId ID) {
- UnknownStructFieldMap[Struct].push_back(std::make_pair(I, ID));
-}
-
-std::istream &
-operator>> (std::istream &I, SPIRVModule &M) {
- SPIRVDecoder Decoder(I, M);
- SPIRVModuleImpl &MI = *static_cast<SPIRVModuleImpl*>(&M);
- // Disable automatic capability filling.
- MI.setAutoAddCapability(false);
-
- SPIRVWord Magic;
- Decoder >> Magic;
- assert(Magic == MagicNumber && "Invalid magic number");
-
- Decoder >> MI.SPIRVVersion;
- assert(MI.SPIRVVersion <= SPV_VERSION && "Unsupported SPIRV version number");
-
- SPIRVWord Generator = 0;
- Decoder >> Generator;
- MI.GeneratorId = Generator >> 16;
- MI.GeneratorVer = Generator & 0xFFFF;
-
- // Bound for Id
- Decoder >> MI.NextId;
-
- Decoder >> MI.InstSchema;
- assert(MI.InstSchema == SPIRVISCH_Default && "Unsupported instruction schema");
-
- while (Decoder.getWordCountAndOpCode()) {
- SPIRVEntry *Entry = Decoder.getEntry();
- if (Entry != nullptr)
- M.add(Entry);
- }
-
- MI.optimizeDecorates();
- MI.resolveUnknownStructFields();
- MI.createForwardPointers();
- return I;
-}
-
-SPIRVModule *
-SPIRVModule::createSPIRVModule() {
- return new SPIRVModuleImpl;
-}
-
-SPIRVValue *
-SPIRVModuleImpl::getValue(SPIRVId TheId)const {
- return get<SPIRVValue>(TheId);
-}
-
-SPIRVType *
-SPIRVModuleImpl::getValueType(SPIRVId TheId)const {
- return get<SPIRVValue>(TheId)->getType();
-}
-
-std::vector<SPIRVValue *>
-SPIRVModuleImpl::getValues(const std::vector<SPIRVId>& IdVec)const {
- std::vector<SPIRVValue *> ValueVec;
- for (auto i:IdVec)
- ValueVec.push_back(getValue(i));
- return ValueVec;
-}
-
-std::vector<SPIRVType *>
-SPIRVModuleImpl::getValueTypes(const std::vector<SPIRVId>& IdVec)const {
- std::vector<SPIRVType *> TypeVec;
- for (auto i:IdVec)
- TypeVec.push_back(getValue(i)->getType());
- return TypeVec;
-}
-
-std::vector<SPIRVId>
-SPIRVModuleImpl::getIds(const std::vector<SPIRVEntry *> &ValueVec)const {
- std::vector<SPIRVId> IdVec;
- for (auto i:ValueVec)
- IdVec.push_back(i->getId());
- return IdVec;
-}
-
-std::vector<SPIRVId>
-SPIRVModuleImpl::getIds(const std::vector<SPIRVValue *> &ValueVec)const {
- std::vector<SPIRVId> IdVec;
- for (auto i:ValueVec)
- IdVec.push_back(i->getId());
- return IdVec;
-}
-
-SPIRVInstTemplateBase*
-SPIRVModuleImpl::addInstTemplate(Op OC,
- SPIRVBasicBlock* BB, SPIRVType *Ty) {
- assert (!Ty || !Ty->isTypeVoid());
- SPIRVId Id = Ty ? getId() : SPIRVID_INVALID;
- auto Ins = SPIRVInstTemplateBase::create(OC, Ty, Id, BB, this);
- BB->addInstruction(Ins);
- return Ins;
-}
-
-SPIRVInstTemplateBase*
-SPIRVModuleImpl::addInstTemplate(Op OC,
- const std::vector<SPIRVWord>& Ops, SPIRVBasicBlock* BB, SPIRVType *Ty) {
- assert (!Ty || !Ty->isTypeVoid());
- SPIRVId Id = Ty ? getId() : SPIRVID_INVALID;
- auto Ins = SPIRVInstTemplateBase::create(OC, Ty, Id, Ops, BB, this);
- BB->addInstruction(Ins);
- return Ins;
-}
-
-SPIRVDbgInfo::SPIRVDbgInfo(SPIRVModule *TM)
-:M(TM){
-}
-
-std::string
-SPIRVDbgInfo::getEntryPointFileStr(SPIRVExecutionModelKind EM, unsigned I) {
- if (M->getNumEntryPoints(EM) == 0)
- return "";
- return getFunctionFileStr(M->getEntryPoint(EM, I));
-}
-
-std::string
-SPIRVDbgInfo::getFunctionFileStr(SPIRVFunction *F) {
- if (F->hasLine())
- return F->getLine()->getFileNameStr();
- return "";
-}
-
-unsigned
-SPIRVDbgInfo::getFunctionLineNo(SPIRVFunction *F) {
- if (F->hasLine())
- return F->getLine()->getLine();
- return 0;
-}
-
-bool IsSPIRVBinary(const std::string &Img) {
- if (Img.size() < sizeof(unsigned))
- return false;
- auto Magic = reinterpret_cast<const unsigned*>(Img.data());
- return *Magic == MagicNumber;
-}
-
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
-
-bool ConvertSPIRV(std::istream &IS, spv_ostream &OS,
- std::string &ErrMsg, bool FromText, bool ToText) {
- auto SaveOpt = SPIRVUseTextFormat;
- SPIRVUseTextFormat = FromText;
- SPIRVModuleImpl M;
- IS >> M;
- if (M.getError(ErrMsg) != SPIRVEC_Success) {
- SPIRVUseTextFormat = SaveOpt;
- return false;
- }
- SPIRVUseTextFormat = ToText;
- OS << M;
- if (M.getError(ErrMsg) != SPIRVEC_Success) {
- SPIRVUseTextFormat = SaveOpt;
- return false;
- }
- SPIRVUseTextFormat = SaveOpt;
- return true;
-}
-
-bool IsSPIRVText(const std::string &Img) {
- std::istringstream SS(Img);
- unsigned Magic = 0;
- SS >> Magic;
- if (SS.bad())
- return false;
- return Magic == MagicNumber;
-}
-
-bool ConvertSPIRV(std::string &Input, std::string &Out,
- std::string &ErrMsg, bool ToText) {
- auto FromText = IsSPIRVText(Input);
- if (ToText == FromText) {
- Out = Input;
- return true;
- }
- std::istringstream IS(Input);
-#ifdef _SPIRV_LLVM_API
- llvm::raw_string_ostream OS(Out);
-#else
- std::ostringstream OS;
-#endif
- if (!ConvertSPIRV(IS, OS, ErrMsg, FromText, ToText))
- return false;
- Out = OS.str();
- return true;
-}
-
-#endif // _SPIRV_SUPPORT_TEXT_FMT
-
-}
-
+ assert(I32 == V && "Integer value truncated"); + return getLiteralAsConstant(I32); + } + return addConstant(new SPIRVConstant(this, Ty, getId(), V)); +} + +SPIRVValue * +SPIRVModuleImpl::addFloatConstant(SPIRVTypeFloat *Ty, float V) { + return addConstant(new SPIRVConstant(this, Ty, getId(), V)); +} + +SPIRVValue * +SPIRVModuleImpl::addDoubleConstant(SPIRVTypeFloat *Ty, double V) { + return addConstant(new SPIRVConstant(this, Ty, getId(), V)); +} + +SPIRVValue * +SPIRVModuleImpl::addNullConstant(SPIRVType *Ty) { + return addConstant(new SPIRVConstantNull(this, Ty, getId())); +} + +SPIRVValue * +SPIRVModuleImpl::addCompositeConstant(SPIRVType *Ty, + const std::vector<SPIRVValue*>& Elements) { + return addConstant(new SPIRVConstantComposite(this, Ty, getId(), Elements)); +} + +SPIRVValue * +SPIRVModuleImpl::addUndef(SPIRVType *TheType) { + return addConstant(new SPIRVUndef(this, TheType, getId())); +} + +// Instruction creation functions + +SPIRVInstruction * +SPIRVModuleImpl::addStoreInst(SPIRVValue *Target, SPIRVValue *Source, + const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *BB) { + return BB->addInstruction(new SPIRVStore(Target->getId(), + Source->getId(), TheMemoryAccess, BB)); +} + +SPIRVInstruction * +SPIRVModuleImpl::addSwitchInst(SPIRVValue *Select, SPIRVBasicBlock *Default, + const std::vector<std::pair<std::vector<SPIRVWord>, SPIRVBasicBlock *>>& Pairs, + SPIRVBasicBlock *BB) { + return BB->addInstruction(new SPIRVSwitch(Select, Default, Pairs, BB)); +} +SPIRVInstruction * +SPIRVModuleImpl::addFModInst(SPIRVType *TheType, SPIRVId TheDividend, + SPIRVId TheDivisor, SPIRVBasicBlock *BB) { + return BB->addInstruction(new SPIRVFMod(TheType, getId(), TheDividend, + TheDivisor, BB)); +} + +SPIRVInstruction * +SPIRVModuleImpl::addVectorTimesScalarInst(SPIRVType *TheType, SPIRVId TheVector, + SPIRVId TheScalar, SPIRVBasicBlock *BB) { + return BB->addInstruction(new SPIRVVectorTimesScalar(TheType, getId(), + TheVector, TheScalar, BB)); +} + +SPIRVInstruction * +SPIRVModuleImpl::addGroupInst(Op OpCode, SPIRVType *Type, + Scope Scope, const std::vector<SPIRVValue *> &Ops, + SPIRVBasicBlock *BB) { + assert(!Type || !Type->isTypeVoid()); + auto WordOps = getIds(Ops); + WordOps.insert(WordOps.begin(), Scope); + return addInstTemplate(OpCode, WordOps, BB, Type); +} + +SPIRVInstruction * +SPIRVModuleImpl::addInstruction(SPIRVInstruction *Inst, SPIRVBasicBlock *BB) { + if (BB) + return BB->addInstruction(Inst); + if (Inst->getOpCode() != OpSpecConstantOp) + Inst = createSpecConstantOpInst(Inst); + return static_cast<SPIRVInstruction *>(addConstant(Inst)); +} + +SPIRVInstruction * +SPIRVModuleImpl::addLoadInst(SPIRVValue *Source, + const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVLoad(getId(), Source->getId(), + TheMemoryAccess, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addPhiInst(SPIRVType *Type, + std::vector<SPIRVValue *> IncomingPairs, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVPhi(Type, getId(), IncomingPairs, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addExtInst(SPIRVType *TheType, SPIRVWord BuiltinSet, + SPIRVWord EntryPoint, const std::vector<SPIRVWord> &Args, + SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVExtInst(TheType, getId(), + BuiltinSet, EntryPoint, Args, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addExtInst(SPIRVType *TheType, SPIRVWord BuiltinSet, + SPIRVWord EntryPoint, const std::vector<SPIRVValue *> &Args, + SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVExtInst(TheType, getId(), + BuiltinSet, EntryPoint, Args, BB), BB); +} + +SPIRVInstruction* +SPIRVModuleImpl::addCallInst(SPIRVFunction* TheFunction, + const std::vector<SPIRVWord> &TheArguments, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVFunctionCall(getId(), TheFunction, + TheArguments, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addBinaryInst(Op TheOpCode, SPIRVType *Type, + SPIRVValue *Op1, SPIRVValue *Op2, SPIRVBasicBlock *BB){ + return addInstruction(SPIRVInstTemplateBase::create(TheOpCode, Type, getId(), + getVec(Op1->getId(), Op2->getId()), BB, this), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addUnreachableInst(SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVUnreachable(BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addReturnInst(SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVReturn(BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addReturnValueInst(SPIRVValue *ReturnValue, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVReturnValue(ReturnValue, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addUnaryInst(Op TheOpCode, SPIRVType *TheType, + SPIRVValue *Op, SPIRVBasicBlock *BB) { + return addInstruction(SPIRVInstTemplateBase::create(TheOpCode, + TheType, getId(), getVec(Op->getId()), BB, this), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addVectorExtractDynamicInst(SPIRVValue *TheVector, + SPIRVValue *Index, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVVectorExtractDynamic(getId(), TheVector, + Index, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addVectorInsertDynamicInst(SPIRVValue *TheVector, +SPIRVValue *TheComponent, SPIRVValue*Index, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVVectorInsertDynamic(getId(), TheVector, + TheComponent, Index, BB), BB); +} + +SPIRVValue * +SPIRVModuleImpl::addVectorShuffleInst(SPIRVType * Type, SPIRVValue *Vec1, + SPIRVValue *Vec2, const std::vector<SPIRVWord> &Components, + SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVVectorShuffle(getId(), Type, Vec1, Vec2, + Components, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addBranchInst(SPIRVLabel *TargetLabel, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVBranch(TargetLabel, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addBranchConditionalInst(SPIRVValue *Condition, + SPIRVLabel *TrueLabel, SPIRVLabel *FalseLabel, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVBranchConditional(Condition, TrueLabel, + FalseLabel, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addCmpInst(Op TheOpCode, SPIRVType *TheType, + SPIRVValue *Op1, SPIRVValue *Op2, SPIRVBasicBlock *BB) { + return addInstruction(SPIRVInstTemplateBase::create(TheOpCode, + TheType, getId(), getVec(Op1->getId(), Op2->getId()), BB, this), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addControlBarrierInst(SPIRVValue *ExecKind, + SPIRVValue *MemKind, SPIRVValue *MemSema, SPIRVBasicBlock *BB) { + return addInstruction( + new SPIRVControlBarrier(ExecKind, MemKind, MemSema, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addLifetimeInst(Op OC, SPIRVValue *Object, SPIRVWord Size, + SPIRVBasicBlock *BB) { + if(OC == OpLifetimeStart) + return BB->addInstruction(new SPIRVLifetimeStart(Object->getId(), + Size, BB)); + else + return BB->addInstruction(new SPIRVLifetimeStop(Object->getId(), + Size, BB)); +} + +SPIRVInstruction * +SPIRVModuleImpl::addMemoryBarrierInst(Scope ScopeKind, + SPIRVWord MemFlag, SPIRVBasicBlock *BB) { + return addInstruction(SPIRVInstTemplateBase::create(OpMemoryBarrier, + nullptr, SPIRVID_INVALID, + getVec(static_cast<SPIRVWord>(ScopeKind), MemFlag), BB, this), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addSelectInst(SPIRVValue *Condition, SPIRVValue *Op1, + SPIRVValue *Op2, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVSelect(getId(), Condition->getId(), + Op1->getId(), Op2->getId(), BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addSelectionMergeInst(SPIRVId MergeBlock, + SPIRVWord SelectionControl, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVSelectionMerge(MergeBlock, SelectionControl, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addLoopMergeInst(SPIRVId MergeBlock, SPIRVId ContinueTarget, + SPIRVWord LoopControl, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVLoopMerge(MergeBlock, ContinueTarget, + LoopControl, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addPtrAccessChainInst(SPIRVType *Type, SPIRVValue *Base, + std::vector<SPIRVValue *> Indices, SPIRVBasicBlock *BB, bool IsInBounds){ + return addInstruction(SPIRVInstTemplateBase::create( + IsInBounds?OpInBoundsPtrAccessChain:OpPtrAccessChain, + Type, getId(), getVec(Base->getId(), Base->getIds(Indices)), + BB, this), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addAsyncGroupCopy(SPIRVValue *Scope, + SPIRVValue *Dest, SPIRVValue *Src, SPIRVValue *NumElems, SPIRVValue *Stride, + SPIRVValue *Event, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVGroupAsyncCopy(Scope, getId(), Dest, Src, + NumElems, Stride, Event, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addCompositeConstructInst(SPIRVType *Type, + const std::vector<SPIRVId>& Constituents, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVCompositeConstruct(Type, getId(), + Constituents, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addCompositeExtractInst(SPIRVType *Type, SPIRVValue *TheVector, + const std::vector<SPIRVWord>& Indices, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVCompositeExtract(Type, getId(), TheVector, + Indices, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addCompositeInsertInst(SPIRVValue *Object, + SPIRVValue *Composite, const std::vector<SPIRVWord>& Indices, + SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVCompositeInsert(getId(), Object, Composite, + Indices, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addCopyObjectInst(SPIRVType *TheType, SPIRVValue *Operand, + SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVCopyObject(TheType, getId(), Operand, BB), BB); + +} + +SPIRVInstruction * +SPIRVModuleImpl::addCopyMemoryInst(SPIRVValue *TheTarget, SPIRVValue *TheSource, + const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVCopyMemory(TheTarget, TheSource, + TheMemoryAccess, BB), BB); +} + +SPIRVInstruction * +SPIRVModuleImpl::addCopyMemorySizedInst(SPIRVValue *TheTarget, + SPIRVValue *TheSource, SPIRVValue *TheSize, + const std::vector<SPIRVWord> &TheMemoryAccess, SPIRVBasicBlock *BB) { + return addInstruction(new SPIRVCopyMemorySized(TheTarget, TheSource, TheSize, + TheMemoryAccess, BB), BB); +} + +SPIRVInstruction* +SPIRVModuleImpl::addVariable(SPIRVType *Type, bool IsConstant, + SPIRVLinkageTypeKind LinkageType, SPIRVValue *Initializer, + const std::string &Name, SPIRVStorageClassKind StorageClass, + SPIRVBasicBlock *BB) { + SPIRVVariable *Variable = new SPIRVVariable(Type, getId(), Initializer, + Name, StorageClass, BB, this); + if (BB) + return addInstruction(Variable, BB); + + add(Variable); + if (LinkageType != LinkageTypeInternal) + Variable->setLinkageType(LinkageType); + Variable->setIsConstant(IsConstant); + return Variable; +} + +template<class T> +spv_ostream & +operator<< (spv_ostream &O, const std::vector<T *>& V) { + for (auto &I: V) + O << *I; + return O; +} + +template<class T, class B> +spv_ostream & +operator<< (spv_ostream &O, const std::multiset<T *, B>& V) { + for (auto &I: V) + O << *I; + return O; +} + +// To satisfy SPIR-V spec requirement: +// "All operands must be declared before being used", +// we do DFS based topological sort +// https://en.wikipedia.org/wiki/Topological_sorting#Depth-first_search +class TopologicalSort { + enum DFSState : char { + Unvisited, + Discovered, + Visited + }; + typedef std::vector<SPIRVType *> SPIRVTypeVec; + typedef std::vector<SPIRVValue *> SPIRVConstantVector; + typedef std::vector<SPIRVVariable *> SPIRVVariableVec; + typedef std::vector<SPIRVEntry *> SPIRVConstAndVarVec; + typedef std::vector<SPIRVTypeForwardPointer *> SPIRVForwardPointerVec; + typedef std::function<bool(SPIRVEntry*, SPIRVEntry*)> IdComp; + typedef std::map<SPIRVEntry*, DFSState, IdComp> EntryStateMapTy; + + SPIRVTypeVec TypeIntVec; + SPIRVConstantVector ConstIntVec; + SPIRVTypeVec TypeVec; + SPIRVConstAndVarVec ConstAndVarVec; + const SPIRVForwardPointerVec& ForwardPointerVec; + EntryStateMapTy EntryStateMap; + + friend spv_ostream & operator<<(spv_ostream &O, const TopologicalSort &S); + +// This method implements recursive depth-first search among all Entries in +// EntryStateMap. Traversing entries and adding them to corresponding container +// after visiting all dependent entries(post-order traversal) guarantees that +// the entry's operands will appear in the container before the entry itslef. + void visit(SPIRVEntry* E) { + DFSState& State = EntryStateMap[E]; + assert(State != Discovered && "Cyclic dependency detected"); + if (State == Visited) + return; + State = Discovered; + for (SPIRVEntry *Op : E->getNonLiteralOperands()) { + auto Comp = [&Op](SPIRVTypeForwardPointer *FwdPtr) { + return FwdPtr->getPointer() == Op; + }; + // Skip forward referenced pointers + if (Op->getOpCode() == OpTypePointer && + find_if(ForwardPointerVec.begin(), ForwardPointerVec.end(), Comp) != + ForwardPointerVec.end()) + continue; + visit(Op); + } + State = Visited; + Op OC = E->getOpCode(); + if (OC == OpTypeInt) + TypeIntVec.push_back(static_cast<SPIRVType*>(E)); + else if (isConstantOpCode(OC)) { + SPIRVConstant *C = static_cast<SPIRVConstant*>(E); + if (C->getType()->isTypeInt()) + ConstIntVec.push_back(C); + else + ConstAndVarVec.push_back(E); + } else if (isTypeOpCode(OC)) + TypeVec.push_back(static_cast<SPIRVType*>(E)); + else + ConstAndVarVec.push_back(E); + } +public: + TopologicalSort(const SPIRVTypeVec &_TypeVec, + const SPIRVConstantVector &_ConstVec, + const SPIRVVariableVec &_VariableVec, + const SPIRVForwardPointerVec &_ForwardPointerVec) : + ForwardPointerVec(_ForwardPointerVec), + EntryStateMap([](SPIRVEntry* a, SPIRVEntry* b) -> bool { + return a->getId() < b->getId(); + }) + { + // Collect entries for sorting + for (auto *T : _TypeVec) + EntryStateMap[T] = DFSState::Unvisited; + for (auto *C : _ConstVec) + EntryStateMap[C] = DFSState::Unvisited; + for (auto *V : _VariableVec) + EntryStateMap[V] = DFSState::Unvisited; + // Run topoligical sort + for (auto ES : EntryStateMap) + visit(ES.first); + } +}; + +spv_ostream & +operator<< (spv_ostream &O, const TopologicalSort &S) { + O << S.TypeIntVec + << S.ConstIntVec + << S.TypeVec + << S.ConstAndVarVec; + return O; +} + +spv_ostream & +operator<< (spv_ostream &O, SPIRVModule &M) { + SPIRVModuleImpl &MI = *static_cast<SPIRVModuleImpl*>(&M); + + SPIRVEncoder Encoder(O); + Encoder << MagicNumber + << MI.SPIRVVersion + << (((SPIRVWord)MI.GeneratorId << 16) | MI.GeneratorVer) + << MI.NextId /* Bound for Id */ + << MI.InstSchema; + O << SPIRVNL(); + + for (auto &I:MI.CapMap) + O << *I.second; + + for (auto &I:M.getExtension()) { + assert(!I.empty() && "Invalid extension"); + O << SPIRVExtension(&M, I); + } + + for (auto &I:MI.IdBuiltinMap) + O << SPIRVExtInstImport(&M, I.first, SPIRVBuiltinSetNameMap::map(I.second)); + + O << SPIRVMemoryModel(&M); + + for (auto &I:MI.EntryPointVec) + for (auto &II:I.second) + O << SPIRVEntryPoint(&M, I.first, II, + M.get<SPIRVFunction>(II)->getName()); + + for (auto &I:MI.EntryPointVec) + for (auto &II:I.second) + MI.get<SPIRVFunction>(II)->encodeExecutionModes(O); + + O << MI.StringVec; + + for (auto &I:M.getSourceExtension()) { + assert(!I.empty() && "Invalid source extension"); + O << SPIRVSourceExtension(&M, I); + } + + O << SPIRVSource(&M); + + for (auto &I:MI.NamedId) { + // Don't output name for entry point since it is redundant + bool IsEntryPoint = false; + for (auto &EPS:MI.EntryPointSet) + if (EPS.second.count(I)) { + IsEntryPoint = true; + break; + } + if (!IsEntryPoint) + M.getEntry(I)->encodeName(O); + } + + O << MI.MemberNameVec + << MI.DecGroupVec + << MI.DecorateSet + << MI.GroupDecVec + << MI.ForwardPointerVec + << TopologicalSort(MI.TypeVec, MI.ConstVec, MI.VariableVec, + MI.ForwardPointerVec) + << SPIRVNL() + << MI.FuncVec; + return O; +} + +template<class T> +void SPIRVModuleImpl::addTo(std::vector<T*>& V, SPIRVEntry* E) { + V.push_back(static_cast<T *>(E)); +} + +// The first decoration group includes all the previously defined decorates. +// The second decoration group includes all the decorates defined between the +// first and second decoration group. So long so forth. +SPIRVDecorationGroup* +SPIRVModuleImpl::addDecorationGroup() { + return addDecorationGroup(new SPIRVDecorationGroup(this, getId())); +} + +SPIRVDecorationGroup* +SPIRVModuleImpl::addDecorationGroup(SPIRVDecorationGroup* Group) { + add(Group); + Group->takeDecorates(DecorateSet); + DecGroupVec.push_back(Group); + SPIRVDBG(spvdbgs() << "[addDecorationGroup] {" << *Group << "}\n"; + spvdbgs() << " Remaining DecorateSet: {" << DecorateSet << "}\n"); + assert(DecorateSet.empty()); + return Group; +} + +SPIRVGroupDecorateGeneric* +SPIRVModuleImpl::addGroupDecorateGeneric(SPIRVGroupDecorateGeneric *GDec) { + add(GDec); + GDec->decorateTargets(); + GroupDecVec.push_back(GDec); + return GDec; +} +SPIRVGroupDecorate* +SPIRVModuleImpl::addGroupDecorate( + SPIRVDecorationGroup* Group, const std::vector<SPIRVEntry*>& Targets) { + auto GD = new SPIRVGroupDecorate(Group, getIds(Targets)); + addGroupDecorateGeneric(GD); + return GD; +} + +SPIRVGroupMemberDecorate* +SPIRVModuleImpl::addGroupMemberDecorate( + SPIRVDecorationGroup* Group, const std::vector<SPIRVEntry*>& Targets) { + auto GMD = new SPIRVGroupMemberDecorate(Group, getIds(Targets)); + addGroupDecorateGeneric(GMD); + return GMD; +} + +SPIRVString* +SPIRVModuleImpl::getString(const std::string& Str) { + auto Loc = StrMap.find(Str); + if (Loc != StrMap.end()) + return Loc->second; + auto S = add(new SPIRVString(this, getId(), Str)); + StrMap[Str] = S; + return S; +} + +SPIRVMemberName* +SPIRVModuleImpl::addMemberName(SPIRVTypeStruct* ST, + SPIRVWord MemberNumber, const std::string& Name) { + return add(new SPIRVMemberName(ST, MemberNumber, Name)); +} + +void SPIRVModuleImpl::addUnknownStructField(SPIRVTypeStruct *Struct, unsigned I, + SPIRVId ID) { + UnknownStructFieldMap[Struct].push_back(std::make_pair(I, ID)); +} + +std::istream & +operator>> (std::istream &I, SPIRVModule &M) { + SPIRVDecoder Decoder(I, M); + SPIRVModuleImpl &MI = *static_cast<SPIRVModuleImpl*>(&M); + // Disable automatic capability filling. + MI.setAutoAddCapability(false); + + SPIRVWord Magic; + Decoder >> Magic; + assert(Magic == MagicNumber && "Invalid magic number"); + + Decoder >> MI.SPIRVVersion; + assert(MI.SPIRVVersion <= SPV_VERSION && "Unsupported SPIRV version number"); + + SPIRVWord Generator = 0; + Decoder >> Generator; + MI.GeneratorId = Generator >> 16; + MI.GeneratorVer = Generator & 0xFFFF; + + // Bound for Id + Decoder >> MI.NextId; + + Decoder >> MI.InstSchema; + assert(MI.InstSchema == SPIRVISCH_Default && "Unsupported instruction schema"); + + while (Decoder.getWordCountAndOpCode()) { + SPIRVEntry *Entry = Decoder.getEntry(); + if (Entry != nullptr) + M.add(Entry); + } + + MI.optimizeDecorates(); + MI.resolveUnknownStructFields(); + MI.createForwardPointers(); + return I; +} + +SPIRVModule * +SPIRVModule::createSPIRVModule() { + return new SPIRVModuleImpl; +} + +SPIRVValue * +SPIRVModuleImpl::getValue(SPIRVId TheId)const { + return get<SPIRVValue>(TheId); +} + +SPIRVType * +SPIRVModuleImpl::getValueType(SPIRVId TheId)const { + return get<SPIRVValue>(TheId)->getType(); +} + +std::vector<SPIRVValue *> +SPIRVModuleImpl::getValues(const std::vector<SPIRVId>& IdVec)const { + std::vector<SPIRVValue *> ValueVec; + for (auto i:IdVec) + ValueVec.push_back(getValue(i)); + return ValueVec; +} + +std::vector<SPIRVType *> +SPIRVModuleImpl::getValueTypes(const std::vector<SPIRVId>& IdVec)const { + std::vector<SPIRVType *> TypeVec; + for (auto i:IdVec) + TypeVec.push_back(getValue(i)->getType()); + return TypeVec; +} + +std::vector<SPIRVId> +SPIRVModuleImpl::getIds(const std::vector<SPIRVEntry *> &ValueVec)const { + std::vector<SPIRVId> IdVec; + for (auto i:ValueVec) + IdVec.push_back(i->getId()); + return IdVec; +} + +std::vector<SPIRVId> +SPIRVModuleImpl::getIds(const std::vector<SPIRVValue *> &ValueVec)const { + std::vector<SPIRVId> IdVec; + for (auto i:ValueVec) + IdVec.push_back(i->getId()); + return IdVec; +} + +SPIRVInstTemplateBase* +SPIRVModuleImpl::addInstTemplate(Op OC, + SPIRVBasicBlock* BB, SPIRVType *Ty) { + assert (!Ty || !Ty->isTypeVoid()); + SPIRVId Id = Ty ? getId() : SPIRVID_INVALID; + auto Ins = SPIRVInstTemplateBase::create(OC, Ty, Id, BB, this); + BB->addInstruction(Ins); + return Ins; +} + +SPIRVInstTemplateBase* +SPIRVModuleImpl::addInstTemplate(Op OC, + const std::vector<SPIRVWord>& Ops, SPIRVBasicBlock* BB, SPIRVType *Ty) { + assert (!Ty || !Ty->isTypeVoid()); + SPIRVId Id = Ty ? getId() : SPIRVID_INVALID; + auto Ins = SPIRVInstTemplateBase::create(OC, Ty, Id, Ops, BB, this); + BB->addInstruction(Ins); + return Ins; +} + +SPIRVDbgInfo::SPIRVDbgInfo(SPIRVModule *TM) +:M(TM){ +} + +std::string +SPIRVDbgInfo::getEntryPointFileStr(SPIRVExecutionModelKind EM, unsigned I) { + if (M->getNumEntryPoints(EM) == 0) + return ""; + return getFunctionFileStr(M->getEntryPoint(EM, I)); +} + +std::string +SPIRVDbgInfo::getFunctionFileStr(SPIRVFunction *F) { + if (F->hasLine()) + return F->getLine()->getFileNameStr(); + return ""; +} + +unsigned +SPIRVDbgInfo::getFunctionLineNo(SPIRVFunction *F) { + if (F->hasLine()) + return F->getLine()->getLine(); + return 0; +} + +bool IsSPIRVBinary(const std::string &Img) { + if (Img.size() < sizeof(unsigned)) + return false; + auto Magic = reinterpret_cast<const unsigned*>(Img.data()); + return *Magic == MagicNumber; +} + +#ifdef _SPIRV_SUPPORT_TEXT_FMT + +bool ConvertSPIRV(std::istream &IS, spv_ostream &OS, + std::string &ErrMsg, bool FromText, bool ToText) { + auto SaveOpt = SPIRVUseTextFormat; + SPIRVUseTextFormat = FromText; + SPIRVModuleImpl M; + IS >> M; + if (M.getError(ErrMsg) != SPIRVEC_Success) { + SPIRVUseTextFormat = SaveOpt; + return false; + } + SPIRVUseTextFormat = ToText; + OS << M; + if (M.getError(ErrMsg) != SPIRVEC_Success) { + SPIRVUseTextFormat = SaveOpt; + return false; + } + SPIRVUseTextFormat = SaveOpt; + return true; +} + +bool IsSPIRVText(const std::string &Img) { + std::istringstream SS(Img); + unsigned Magic = 0; + SS >> Magic; + if (SS.bad()) + return false; + return Magic == MagicNumber; +} + +bool ConvertSPIRV(std::string &Input, std::string &Out, + std::string &ErrMsg, bool ToText) { + auto FromText = IsSPIRVText(Input); + if (ToText == FromText) { + Out = Input; + return true; + } + std::istringstream IS(Input); +#ifdef _SPIRV_LLVM_API + llvm::raw_string_ostream OS(Out); +#else + std::ostringstream OS; +#endif + if (!ConvertSPIRV(IS, OS, ErrMsg, FromText, ToText)) + return false; + Out = OS.str(); + return true; +} + +#endif // _SPIRV_SUPPORT_TEXT_FMT + +} + diff --git a/lib/SPIRV/libSPIRV/SPIRVModule.h b/lib/SPIRV/libSPIRV/SPIRVModule.h index 577893a..3ef7a52 100644 --- a/lib/SPIRV/libSPIRV/SPIRVModule.h +++ b/lib/SPIRV/libSPIRV/SPIRVModule.h @@ -1,362 +1,362 @@ -//===- SPIRVModule.h - Class to represent a SPIR-V module --------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines Module class for SPIR-V.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVMODULE_HPP_
-#define SPIRVMODULE_HPP_
-
-#include "SPIRVEntry.h"
-
-#include <iostream>
-#include <set>
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-namespace SPIRV{
-
-class SPIRVBasicBlock;
-class SPIRVConstant;
-class SPIRVEntry;
-class SPIRVFunction;
-class SPIRVInstruction;
-class SPIRVType;
-class SPIRVTypeArray;
-class SPIRVTypeBool;
-class SPIRVTypeFloat;
-class SPIRVTypeFunction;
-class SPIRVTypeInt;
-class SPIRVTypeOpaque;
-class SPIRVTypePointer;
-class SPIRVTypeImage;
-class SPIRVTypeSampler;
-class SPIRVTypeSampledImage;
-class SPIRVTypePipeStorage;
-class SPIRVTypeStruct;
-class SPIRVTypeVector;
-class SPIRVTypeVoid;
-class SPIRVTypeDeviceEvent;
-class SPIRVTypeQueue;
-class SPIRVTypePipe;
-class SPIRVValue;
-class SPIRVVariable;
-class SPIRVDecorateGeneric;
-class SPIRVDecorationGroup;
-class SPIRVGroupDecorate;
-class SPIRVGroupMemberDecorate;
-class SPIRVGroupDecorateGeneric;
-class SPIRVInstTemplateBase;
-
-typedef SPIRVBasicBlock SPIRVLabel;
-struct SPIRVTypeImageDescriptor;
-
-class SPIRVModule {
-public:
- typedef std::map<SPIRVCapabilityKind, SPIRVCapability*> SPIRVCapMap;
-
- static SPIRVModule* createSPIRVModule();
- SPIRVModule();
- virtual ~SPIRVModule();
-
- // Object query functions
- virtual bool exist(SPIRVId) const = 0;
- virtual bool exist(SPIRVId, SPIRVEntry **)const = 0;
- template<class T> T* get(SPIRVId Id) const {
- return static_cast<T*>(getEntry(Id));}
- virtual SPIRVEntry *getEntry(SPIRVId) const = 0;
- virtual bool hasDebugInfo() const = 0;
-
- // Error handling functions
- virtual SPIRVErrorLog &getErrorLog() = 0;
- virtual SPIRVErrorCode getError(std::string&) = 0;
-
- // Module query functions
- virtual SPIRVAddressingModelKind getAddressingModel() = 0;
- virtual const SPIRVCapMap &getCapability() const = 0;
- virtual bool hasCapability(SPIRVCapabilityKind) const = 0;
- virtual SPIRVExtInstSetKind getBuiltinSet(SPIRVId) const = 0;
- virtual SPIRVFunction *getEntryPoint(SPIRVExecutionModelKind, unsigned) const
- = 0;
- virtual std::set<std::string> &getExtension() = 0;
- virtual SPIRVFunction *getFunction(unsigned) const = 0;
- virtual SPIRVVariable *getVariable(unsigned) const = 0;
- virtual SPIRVMemoryModelKind getMemoryModel() const = 0;
- virtual unsigned getNumFunctions() const = 0;
- virtual unsigned getNumEntryPoints(SPIRVExecutionModelKind) const = 0;
- virtual unsigned getNumVariables() const = 0;
- virtual SourceLanguage getSourceLanguage(SPIRVWord *) const = 0;
- virtual std::set<std::string> &getSourceExtension() = 0;
- virtual SPIRVValue *getValue(SPIRVId TheId)const = 0;
- virtual std::vector<SPIRVValue *> getValues(const std::vector<SPIRVId>&)const
- = 0;
- virtual std::vector<SPIRVId> getIds(const std::vector<SPIRVEntry *>&)const = 0;
- virtual std::vector<SPIRVId> getIds(const std::vector<SPIRVValue *>&)const = 0;
- virtual SPIRVType *getValueType(SPIRVId TheId)const = 0;
- virtual std::vector<SPIRVType *> getValueTypes(const std::vector<SPIRVId>&)
- const = 0;
- virtual SPIRVConstant* getLiteralAsConstant(unsigned Literal) = 0;
- virtual bool isEntryPoint(SPIRVExecutionModelKind, SPIRVId) const = 0;
- virtual unsigned short getGeneratorId() const = 0;
- virtual unsigned short getGeneratorVer() const = 0;
- virtual SPIRVWord getSPIRVVersion() const = 0;
-
- // Module changing functions
- virtual bool importBuiltinSet(const std::string &, SPIRVId *) = 0;
- virtual bool importBuiltinSetWithId(const std::string &, SPIRVId) = 0;
- virtual void setAddressingModel(SPIRVAddressingModelKind) = 0;
- virtual void setAlignment(SPIRVValue *, SPIRVWord) = 0;
- virtual void setMemoryModel(SPIRVMemoryModelKind) = 0;
- virtual void setName(SPIRVEntry *, const std::string&) = 0;
- virtual void setSourceLanguage(SourceLanguage, SPIRVWord) = 0;
- virtual void optimizeDecorates() = 0;
- virtual void setAutoAddCapability(bool E){ AutoAddCapability = E;}
- virtual void setValidateCapability(bool E){ ValidateCapability = E;}
- virtual void setGeneratorId(unsigned short) = 0;
- virtual void setGeneratorVer(unsigned short) = 0;
- virtual void resolveUnknownStructFields() = 0;
- virtual void setSPIRVVersion(SPIRVWord) = 0;
-
- void setMinSPIRVVersion(SPIRVWord Ver) {
- setSPIRVVersion(std::max(Ver, getSPIRVVersion()));
- }
-
- // Object creation functions
- template<class T> T *add(T *Entry) { addEntry(Entry); return Entry;}
- virtual SPIRVEntry *addEntry(SPIRVEntry *) = 0;
- virtual SPIRVBasicBlock *addBasicBlock(SPIRVFunction *,
- SPIRVId Id = SPIRVID_INVALID) = 0;
- virtual SPIRVString *getString(const std::string &Str) = 0;
- virtual SPIRVMemberName *addMemberName(SPIRVTypeStruct *ST,
- SPIRVWord MemberNumber, const std::string &Name) = 0;
- virtual void addUnknownStructField(SPIRVTypeStruct *, unsigned idx,
- SPIRVId id) = 0;
- virtual void addLine(SPIRVEntry *E, SPIRVId FileNameId, SPIRVWord Line,
- SPIRVWord Column) = 0;
- virtual const std::shared_ptr<const SPIRVLine>& getCurrentLine() const = 0;
- virtual void setCurrentLine(const std::shared_ptr<const SPIRVLine>&) = 0;
- virtual const SPIRVDecorateGeneric *addDecorate(SPIRVDecorateGeneric*)
- = 0;
- virtual SPIRVDecorationGroup *addDecorationGroup() = 0;
- virtual SPIRVDecorationGroup *addDecorationGroup(SPIRVDecorationGroup *Group)
- = 0;
- virtual SPIRVGroupDecorate *addGroupDecorate(SPIRVDecorationGroup *Group,
- const std::vector<SPIRVEntry *> &Targets) = 0;
- virtual SPIRVGroupMemberDecorate *addGroupMemberDecorate(
- SPIRVDecorationGroup *Group, const std::vector<SPIRVEntry *> &Targets) = 0;
- virtual SPIRVGroupDecorateGeneric *addGroupDecorateGeneric(
- SPIRVGroupDecorateGeneric *GDec) = 0;
- virtual void addEntryPoint(SPIRVExecutionModelKind, SPIRVId) = 0;
- virtual SPIRVForward *addForward(SPIRVType *Ty) = 0;
- virtual SPIRVForward *addForward(SPIRVId, SPIRVType *Ty) = 0;
- virtual SPIRVFunction *addFunction(SPIRVFunction *) = 0;
- virtual SPIRVFunction *addFunction(SPIRVTypeFunction *,
- SPIRVId Id = SPIRVID_INVALID) = 0;
- virtual SPIRVEntry *replaceForward(SPIRVForward *, SPIRVEntry *) = 0;
- virtual void eraseInstruction(SPIRVInstruction *, SPIRVBasicBlock *) = 0;
-
- // Type creation functions
- virtual SPIRVTypeArray *addArrayType(SPIRVType *, SPIRVConstant *) = 0;
- virtual SPIRVTypeBool *addBoolType() = 0;
- virtual SPIRVTypeFloat *addFloatType(unsigned) = 0;
- virtual SPIRVTypeFunction *addFunctionType(SPIRVType *,
- const std::vector<SPIRVType *> &) = 0;
- virtual SPIRVTypeImage *addImageType(SPIRVType *,
- const SPIRVTypeImageDescriptor &) = 0;
- virtual SPIRVTypeImage *addImageType(SPIRVType *,
- const SPIRVTypeImageDescriptor &, SPIRVAccessQualifierKind) = 0;
- virtual SPIRVTypeSampler *addSamplerType() = 0;
- virtual SPIRVTypePipeStorage *addPipeStorageType() = 0;
- virtual SPIRVTypeSampledImage *addSampledImageType(SPIRVTypeImage *T) = 0;
- virtual SPIRVTypeInt *addIntegerType(unsigned) = 0;
- virtual SPIRVTypeOpaque *addOpaqueType(const std::string &) = 0;
- virtual SPIRVTypePointer *addPointerType(SPIRVStorageClassKind, SPIRVType *) = 0;
- virtual SPIRVTypeStruct *openStructType(unsigned, const std::string &) = 0;
- virtual void closeStructType(SPIRVTypeStruct *, bool) = 0;
- virtual SPIRVTypeVector *addVectorType(SPIRVType *, SPIRVWord) = 0;
- virtual SPIRVTypeVoid *addVoidType() = 0;
- virtual SPIRVType *addOpaqueGenericType(Op) = 0;
- virtual SPIRVTypeDeviceEvent *addDeviceEventType() = 0;
- virtual SPIRVTypeQueue *addQueueType() = 0;
- virtual SPIRVTypePipe *addPipeType() = 0;
- virtual void createForwardPointers() = 0;
-
- // Constants creation functions
- virtual SPIRVValue *addCompositeConstant(SPIRVType *,
- const std::vector<SPIRVValue*>&) = 0;
- virtual SPIRVValue *addConstant(SPIRVValue *) = 0;
- virtual SPIRVValue *addConstant(SPIRVType *, uint64_t) = 0;
- virtual SPIRVValue *addDoubleConstant(SPIRVTypeFloat *, double) = 0;
- virtual SPIRVValue *addFloatConstant(SPIRVTypeFloat *, float) = 0;
- virtual SPIRVValue *addIntegerConstant(SPIRVTypeInt *, uint64_t) = 0;
- virtual SPIRVValue *addNullConstant(SPIRVType *) = 0;
- virtual SPIRVValue *addUndef(SPIRVType *TheType) = 0;
- virtual SPIRVValue *addSamplerConstant(SPIRVType *TheType, SPIRVWord AddrMode,
- SPIRVWord ParametricMode, SPIRVWord FilterMode) = 0;
- virtual SPIRVValue* addPipeStorageConstant(SPIRVType* TheType,
- SPIRVWord PacketSize, SPIRVWord PacketAlign, SPIRVWord Capacity) = 0;
-
- // Instruction creation functions
- virtual SPIRVInstruction *addPtrAccessChainInst(SPIRVType *, SPIRVValue *,
- std::vector<SPIRVValue *>, SPIRVBasicBlock *, bool) = 0;
- virtual SPIRVInstruction *addAsyncGroupCopy(SPIRVValue *Scope,
- SPIRVValue *Dest, SPIRVValue *Src, SPIRVValue *NumElems, SPIRVValue *Stride,
- SPIRVValue *Event, SPIRVBasicBlock *BB) = 0;
- virtual SPIRVInstruction *addBinaryInst(Op, SPIRVType *, SPIRVValue *,
- SPIRVValue *, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addBranchConditionalInst(SPIRVValue *, SPIRVLabel *,
- SPIRVLabel *, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addBranchInst(SPIRVLabel *, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addExtInst(SPIRVType *, SPIRVWord, SPIRVWord,
- const std::vector<SPIRVWord> &, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addExtInst(SPIRVType *, SPIRVWord, SPIRVWord,
- const std::vector<SPIRVValue *> &, SPIRVBasicBlock *) = 0;
- virtual void addCapability(SPIRVCapabilityKind) = 0;
- template<typename T>
- void addCapabilities(const T& Caps) {
- for (auto I: Caps)
- addCapability(I);
- }
- /// Used by SPIRV entries to add required capability internally.
- /// Should not be used by users directly.
- virtual void addCapabilityInternal(SPIRVCapabilityKind) = 0;
- virtual SPIRVInstruction *addCallInst(SPIRVFunction*,
- const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addCompositeConstructInst(SPIRVType *,
- const std::vector<SPIRVId>&, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addCompositeExtractInst(SPIRVType *, SPIRVValue *,
- const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addCompositeInsertInst(SPIRVValue *,
- SPIRVValue *, const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addCopyObjectInst(SPIRVType *, SPIRVValue *,
- SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addCopyMemoryInst(SPIRVValue *, SPIRVValue *,
- const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addCopyMemorySizedInst(SPIRVValue *, SPIRVValue *,
- SPIRVValue *, const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addCmpInst(Op, SPIRVType *, SPIRVValue *,
- SPIRVValue *, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addControlBarrierInst(
- SPIRVValue *ExecKind, SPIRVValue *MemKind,
- SPIRVValue *MemSema, SPIRVBasicBlock *BB) = 0;
- virtual SPIRVInstruction *addGroupInst(Op OpCode, SPIRVType *Type,
- Scope Scope, const std::vector<SPIRVValue *> &Ops,
- SPIRVBasicBlock *BB) = 0;
- virtual SPIRVInstTemplateBase* addInstTemplate(Op OC,
- SPIRVBasicBlock* BB, SPIRVType *Ty) = 0;
- virtual SPIRVInstTemplateBase* addInstTemplate(Op OC,
- const std::vector<SPIRVWord>& Ops, SPIRVBasicBlock* BB, SPIRVType *Ty) = 0;
- virtual SPIRVInstruction *addLoadInst(SPIRVValue *,
- const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addLifetimeInst(Op OC, SPIRVValue *Object,
- SPIRVWord Size, SPIRVBasicBlock *BB) = 0;
- virtual SPIRVInstruction *addMemoryBarrierInst(
- Scope ScopeKind, SPIRVWord MemFlag, SPIRVBasicBlock *BB)
- = 0;
- virtual SPIRVInstruction *addPhiInst(SPIRVType *, std::vector<SPIRVValue *>,
- SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addUnreachableInst(SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addReturnInst(SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addReturnValueInst(SPIRVValue *, SPIRVBasicBlock *)
- = 0;
- virtual SPIRVInstruction *addSelectInst(SPIRVValue *, SPIRVValue *, SPIRVValue *,
- SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addSelectionMergeInst(SPIRVId MergeBlock,
- SPIRVWord SelectionControl, SPIRVBasicBlock *BB) = 0;
- virtual SPIRVInstruction *addLoopMergeInst(SPIRVId MergeBlock,
- SPIRVId ContinueTarget, SPIRVWord LoopControl, SPIRVBasicBlock *BB) = 0;
- virtual SPIRVInstruction *addStoreInst(SPIRVValue *, SPIRVValue *,
- const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addSwitchInst(SPIRVValue *, SPIRVBasicBlock *,
- const std::vector<std::pair<std::vector<SPIRVWord>, SPIRVBasicBlock *>>&,
- SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addFModInst(SPIRVType *TheType, SPIRVId TheDividend,
- SPIRVId TheDivisor, SPIRVBasicBlock *BB) = 0;
- virtual SPIRVInstruction *addVectorTimesScalarInst(SPIRVType *TheType, SPIRVId TheVector,
- SPIRVId TheScalar, SPIRVBasicBlock *BB) = 0;
- virtual SPIRVInstruction *addUnaryInst(Op, SPIRVType *, SPIRVValue *,
- SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addVariable(SPIRVType *, bool, SPIRVLinkageTypeKind,
- SPIRVValue *, const std::string &, SPIRVStorageClassKind, SPIRVBasicBlock *)
- = 0;
- virtual SPIRVValue *addVectorShuffleInst(SPIRVType *Type, SPIRVValue *Vec1,
- SPIRVValue *Vec2, const std::vector<SPIRVWord> &Components,
- SPIRVBasicBlock *BB) = 0;
- virtual SPIRVInstruction *addVectorExtractDynamicInst(SPIRVValue *,
- SPIRVValue *, SPIRVBasicBlock *) = 0;
- virtual SPIRVInstruction *addVectorInsertDynamicInst(SPIRVValue *,
- SPIRVValue *, SPIRVValue*, SPIRVBasicBlock *) = 0;
- // I/O functions
- friend spv_ostream & operator<<(spv_ostream &O, SPIRVModule& M);
- friend std::istream & operator>>(std::istream &I, SPIRVModule& M);
-protected:
- bool AutoAddCapability;
- bool ValidateCapability;
-};
-
-class SPIRVDbgInfo {
-public:
- SPIRVDbgInfo(SPIRVModule *TM);
- std::string getEntryPointFileStr(SPIRVExecutionModelKind, unsigned);
- std::string getFunctionFileStr(SPIRVFunction *);
- unsigned getFunctionLineNo(SPIRVFunction *);
-private:
- std::unordered_map<SPIRVFunction *, SPIRVLine *> FuncMap;
- const std::string ModuleFileStr;
- SPIRVModule *M;
-};
-
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
-
-/// Convert SPIR-V between binary and internel text formats.
-/// This function is not thread safe and should not be used in multi-thread
-/// applications unless guarded by a critical section.
-bool ConvertSPIRV(std::istream &IS, spv_ostream &OS,
- std::string &ErrMsg, bool FromText, bool ToText);
-
-/// Convert SPIR-V between binary and internel text formats.
-/// This function is not thread safe and should not be used in multi-thread
-/// applications unless guarded by a critical section.
-bool ConvertSPIRV(std::string &Input, std::string &Out,
- std::string &ErrMsg, bool ToText);
-#endif
-}
-
-
-
-#endif /* SPIRVMODULE_HPP_ */
+//===- SPIRVModule.h - Class to represent a SPIR-V module --------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines Module class for SPIR-V. +/// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVMODULE_HPP_ +#define SPIRVMODULE_HPP_ + +#include "SPIRVEntry.h" + +#include <iostream> +#include <set> +#include <string> +#include <unordered_map> +#include <unordered_set> +#include <vector> + +namespace SPIRV{ + +class SPIRVBasicBlock; +class SPIRVConstant; +class SPIRVEntry; +class SPIRVFunction; +class SPIRVInstruction; +class SPIRVType; +class SPIRVTypeArray; +class SPIRVTypeBool; +class SPIRVTypeFloat; +class SPIRVTypeFunction; +class SPIRVTypeInt; +class SPIRVTypeOpaque; +class SPIRVTypePointer; +class SPIRVTypeImage; +class SPIRVTypeSampler; +class SPIRVTypeSampledImage; +class SPIRVTypePipeStorage; +class SPIRVTypeStruct; +class SPIRVTypeVector; +class SPIRVTypeVoid; +class SPIRVTypeDeviceEvent; +class SPIRVTypeQueue; +class SPIRVTypePipe; +class SPIRVValue; +class SPIRVVariable; +class SPIRVDecorateGeneric; +class SPIRVDecorationGroup; +class SPIRVGroupDecorate; +class SPIRVGroupMemberDecorate; +class SPIRVGroupDecorateGeneric; +class SPIRVInstTemplateBase; + +typedef SPIRVBasicBlock SPIRVLabel; +struct SPIRVTypeImageDescriptor; + +class SPIRVModule { +public: + typedef std::map<SPIRVCapabilityKind, SPIRVCapability*> SPIRVCapMap; + + static SPIRVModule* createSPIRVModule(); + SPIRVModule(); + virtual ~SPIRVModule(); + + // Object query functions + virtual bool exist(SPIRVId) const = 0; + virtual bool exist(SPIRVId, SPIRVEntry **)const = 0; + template<class T> T* get(SPIRVId Id) const { + return static_cast<T*>(getEntry(Id));} + virtual SPIRVEntry *getEntry(SPIRVId) const = 0; + virtual bool hasDebugInfo() const = 0; + + // Error handling functions + virtual SPIRVErrorLog &getErrorLog() = 0; + virtual SPIRVErrorCode getError(std::string&) = 0; + + // Module query functions + virtual SPIRVAddressingModelKind getAddressingModel() = 0; + virtual const SPIRVCapMap &getCapability() const = 0; + virtual bool hasCapability(SPIRVCapabilityKind) const = 0; + virtual SPIRVExtInstSetKind getBuiltinSet(SPIRVId) const = 0; + virtual SPIRVFunction *getEntryPoint(SPIRVExecutionModelKind, unsigned) const + = 0; + virtual std::set<std::string> &getExtension() = 0; + virtual SPIRVFunction *getFunction(unsigned) const = 0; + virtual SPIRVVariable *getVariable(unsigned) const = 0; + virtual SPIRVMemoryModelKind getMemoryModel() const = 0; + virtual unsigned getNumFunctions() const = 0; + virtual unsigned getNumEntryPoints(SPIRVExecutionModelKind) const = 0; + virtual unsigned getNumVariables() const = 0; + virtual SourceLanguage getSourceLanguage(SPIRVWord *) const = 0; + virtual std::set<std::string> &getSourceExtension() = 0; + virtual SPIRVValue *getValue(SPIRVId TheId)const = 0; + virtual std::vector<SPIRVValue *> getValues(const std::vector<SPIRVId>&)const + = 0; + virtual std::vector<SPIRVId> getIds(const std::vector<SPIRVEntry *>&)const = 0; + virtual std::vector<SPIRVId> getIds(const std::vector<SPIRVValue *>&)const = 0; + virtual SPIRVType *getValueType(SPIRVId TheId)const = 0; + virtual std::vector<SPIRVType *> getValueTypes(const std::vector<SPIRVId>&) + const = 0; + virtual SPIRVConstant* getLiteralAsConstant(unsigned Literal) = 0; + virtual bool isEntryPoint(SPIRVExecutionModelKind, SPIRVId) const = 0; + virtual unsigned short getGeneratorId() const = 0; + virtual unsigned short getGeneratorVer() const = 0; + virtual SPIRVWord getSPIRVVersion() const = 0; + + // Module changing functions + virtual bool importBuiltinSet(const std::string &, SPIRVId *) = 0; + virtual bool importBuiltinSetWithId(const std::string &, SPIRVId) = 0; + virtual void setAddressingModel(SPIRVAddressingModelKind) = 0; + virtual void setAlignment(SPIRVValue *, SPIRVWord) = 0; + virtual void setMemoryModel(SPIRVMemoryModelKind) = 0; + virtual void setName(SPIRVEntry *, const std::string&) = 0; + virtual void setSourceLanguage(SourceLanguage, SPIRVWord) = 0; + virtual void optimizeDecorates() = 0; + virtual void setAutoAddCapability(bool E){ AutoAddCapability = E;} + virtual void setValidateCapability(bool E){ ValidateCapability = E;} + virtual void setGeneratorId(unsigned short) = 0; + virtual void setGeneratorVer(unsigned short) = 0; + virtual void resolveUnknownStructFields() = 0; + virtual void setSPIRVVersion(SPIRVWord) = 0; + + void setMinSPIRVVersion(SPIRVWord Ver) { + setSPIRVVersion(std::max(Ver, getSPIRVVersion())); + } + + // Object creation functions + template<class T> T *add(T *Entry) { addEntry(Entry); return Entry;} + virtual SPIRVEntry *addEntry(SPIRVEntry *) = 0; + virtual SPIRVBasicBlock *addBasicBlock(SPIRVFunction *, + SPIRVId Id = SPIRVID_INVALID) = 0; + virtual SPIRVString *getString(const std::string &Str) = 0; + virtual SPIRVMemberName *addMemberName(SPIRVTypeStruct *ST, + SPIRVWord MemberNumber, const std::string &Name) = 0; + virtual void addUnknownStructField(SPIRVTypeStruct *, unsigned idx, + SPIRVId id) = 0; + virtual void addLine(SPIRVEntry *E, SPIRVId FileNameId, SPIRVWord Line, + SPIRVWord Column) = 0; + virtual const std::shared_ptr<const SPIRVLine>& getCurrentLine() const = 0; + virtual void setCurrentLine(const std::shared_ptr<const SPIRVLine>&) = 0; + virtual const SPIRVDecorateGeneric *addDecorate(SPIRVDecorateGeneric*) + = 0; + virtual SPIRVDecorationGroup *addDecorationGroup() = 0; + virtual SPIRVDecorationGroup *addDecorationGroup(SPIRVDecorationGroup *Group) + = 0; + virtual SPIRVGroupDecorate *addGroupDecorate(SPIRVDecorationGroup *Group, + const std::vector<SPIRVEntry *> &Targets) = 0; + virtual SPIRVGroupMemberDecorate *addGroupMemberDecorate( + SPIRVDecorationGroup *Group, const std::vector<SPIRVEntry *> &Targets) = 0; + virtual SPIRVGroupDecorateGeneric *addGroupDecorateGeneric( + SPIRVGroupDecorateGeneric *GDec) = 0; + virtual void addEntryPoint(SPIRVExecutionModelKind, SPIRVId) = 0; + virtual SPIRVForward *addForward(SPIRVType *Ty) = 0; + virtual SPIRVForward *addForward(SPIRVId, SPIRVType *Ty) = 0; + virtual SPIRVFunction *addFunction(SPIRVFunction *) = 0; + virtual SPIRVFunction *addFunction(SPIRVTypeFunction *, + SPIRVId Id = SPIRVID_INVALID) = 0; + virtual SPIRVEntry *replaceForward(SPIRVForward *, SPIRVEntry *) = 0; + virtual void eraseInstruction(SPIRVInstruction *, SPIRVBasicBlock *) = 0; + + // Type creation functions + virtual SPIRVTypeArray *addArrayType(SPIRVType *, SPIRVConstant *) = 0; + virtual SPIRVTypeBool *addBoolType() = 0; + virtual SPIRVTypeFloat *addFloatType(unsigned) = 0; + virtual SPIRVTypeFunction *addFunctionType(SPIRVType *, + const std::vector<SPIRVType *> &) = 0; + virtual SPIRVTypeImage *addImageType(SPIRVType *, + const SPIRVTypeImageDescriptor &) = 0; + virtual SPIRVTypeImage *addImageType(SPIRVType *, + const SPIRVTypeImageDescriptor &, SPIRVAccessQualifierKind) = 0; + virtual SPIRVTypeSampler *addSamplerType() = 0; + virtual SPIRVTypePipeStorage *addPipeStorageType() = 0; + virtual SPIRVTypeSampledImage *addSampledImageType(SPIRVTypeImage *T) = 0; + virtual SPIRVTypeInt *addIntegerType(unsigned) = 0; + virtual SPIRVTypeOpaque *addOpaqueType(const std::string &) = 0; + virtual SPIRVTypePointer *addPointerType(SPIRVStorageClassKind, SPIRVType *) = 0; + virtual SPIRVTypeStruct *openStructType(unsigned, const std::string &) = 0; + virtual void closeStructType(SPIRVTypeStruct *, bool) = 0; + virtual SPIRVTypeVector *addVectorType(SPIRVType *, SPIRVWord) = 0; + virtual SPIRVTypeVoid *addVoidType() = 0; + virtual SPIRVType *addOpaqueGenericType(Op) = 0; + virtual SPIRVTypeDeviceEvent *addDeviceEventType() = 0; + virtual SPIRVTypeQueue *addQueueType() = 0; + virtual SPIRVTypePipe *addPipeType() = 0; + virtual void createForwardPointers() = 0; + + // Constants creation functions + virtual SPIRVValue *addCompositeConstant(SPIRVType *, + const std::vector<SPIRVValue*>&) = 0; + virtual SPIRVValue *addConstant(SPIRVValue *) = 0; + virtual SPIRVValue *addConstant(SPIRVType *, uint64_t) = 0; + virtual SPIRVValue *addDoubleConstant(SPIRVTypeFloat *, double) = 0; + virtual SPIRVValue *addFloatConstant(SPIRVTypeFloat *, float) = 0; + virtual SPIRVValue *addIntegerConstant(SPIRVTypeInt *, uint64_t) = 0; + virtual SPIRVValue *addNullConstant(SPIRVType *) = 0; + virtual SPIRVValue *addUndef(SPIRVType *TheType) = 0; + virtual SPIRVValue *addSamplerConstant(SPIRVType *TheType, SPIRVWord AddrMode, + SPIRVWord ParametricMode, SPIRVWord FilterMode) = 0; + virtual SPIRVValue* addPipeStorageConstant(SPIRVType* TheType, + SPIRVWord PacketSize, SPIRVWord PacketAlign, SPIRVWord Capacity) = 0; + + // Instruction creation functions + virtual SPIRVInstruction *addPtrAccessChainInst(SPIRVType *, SPIRVValue *, + std::vector<SPIRVValue *>, SPIRVBasicBlock *, bool) = 0; + virtual SPIRVInstruction *addAsyncGroupCopy(SPIRVValue *Scope, + SPIRVValue *Dest, SPIRVValue *Src, SPIRVValue *NumElems, SPIRVValue *Stride, + SPIRVValue *Event, SPIRVBasicBlock *BB) = 0; + virtual SPIRVInstruction *addBinaryInst(Op, SPIRVType *, SPIRVValue *, + SPIRVValue *, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addBranchConditionalInst(SPIRVValue *, SPIRVLabel *, + SPIRVLabel *, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addBranchInst(SPIRVLabel *, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addExtInst(SPIRVType *, SPIRVWord, SPIRVWord, + const std::vector<SPIRVWord> &, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addExtInst(SPIRVType *, SPIRVWord, SPIRVWord, + const std::vector<SPIRVValue *> &, SPIRVBasicBlock *) = 0; + virtual void addCapability(SPIRVCapabilityKind) = 0; + template<typename T> + void addCapabilities(const T& Caps) { + for (auto I: Caps) + addCapability(I); + } + /// Used by SPIRV entries to add required capability internally. + /// Should not be used by users directly. + virtual void addCapabilityInternal(SPIRVCapabilityKind) = 0; + virtual SPIRVInstruction *addCallInst(SPIRVFunction*, + const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addCompositeConstructInst(SPIRVType *, + const std::vector<SPIRVId>&, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addCompositeExtractInst(SPIRVType *, SPIRVValue *, + const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addCompositeInsertInst(SPIRVValue *, + SPIRVValue *, const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addCopyObjectInst(SPIRVType *, SPIRVValue *, + SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addCopyMemoryInst(SPIRVValue *, SPIRVValue *, + const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addCopyMemorySizedInst(SPIRVValue *, SPIRVValue *, + SPIRVValue *, const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addCmpInst(Op, SPIRVType *, SPIRVValue *, + SPIRVValue *, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addControlBarrierInst( + SPIRVValue *ExecKind, SPIRVValue *MemKind, + SPIRVValue *MemSema, SPIRVBasicBlock *BB) = 0; + virtual SPIRVInstruction *addGroupInst(Op OpCode, SPIRVType *Type, + Scope Scope, const std::vector<SPIRVValue *> &Ops, + SPIRVBasicBlock *BB) = 0; + virtual SPIRVInstTemplateBase* addInstTemplate(Op OC, + SPIRVBasicBlock* BB, SPIRVType *Ty) = 0; + virtual SPIRVInstTemplateBase* addInstTemplate(Op OC, + const std::vector<SPIRVWord>& Ops, SPIRVBasicBlock* BB, SPIRVType *Ty) = 0; + virtual SPIRVInstruction *addLoadInst(SPIRVValue *, + const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addLifetimeInst(Op OC, SPIRVValue *Object, + SPIRVWord Size, SPIRVBasicBlock *BB) = 0; + virtual SPIRVInstruction *addMemoryBarrierInst( + Scope ScopeKind, SPIRVWord MemFlag, SPIRVBasicBlock *BB) + = 0; + virtual SPIRVInstruction *addPhiInst(SPIRVType *, std::vector<SPIRVValue *>, + SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addUnreachableInst(SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addReturnInst(SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addReturnValueInst(SPIRVValue *, SPIRVBasicBlock *) + = 0; + virtual SPIRVInstruction *addSelectInst(SPIRVValue *, SPIRVValue *, SPIRVValue *, + SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addSelectionMergeInst(SPIRVId MergeBlock, + SPIRVWord SelectionControl, SPIRVBasicBlock *BB) = 0; + virtual SPIRVInstruction *addLoopMergeInst(SPIRVId MergeBlock, + SPIRVId ContinueTarget, SPIRVWord LoopControl, SPIRVBasicBlock *BB) = 0; + virtual SPIRVInstruction *addStoreInst(SPIRVValue *, SPIRVValue *, + const std::vector<SPIRVWord>&, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addSwitchInst(SPIRVValue *, SPIRVBasicBlock *, + const std::vector<std::pair<std::vector<SPIRVWord>, SPIRVBasicBlock *>>&, + SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addFModInst(SPIRVType *TheType, SPIRVId TheDividend, + SPIRVId TheDivisor, SPIRVBasicBlock *BB) = 0; + virtual SPIRVInstruction *addVectorTimesScalarInst(SPIRVType *TheType, SPIRVId TheVector, + SPIRVId TheScalar, SPIRVBasicBlock *BB) = 0; + virtual SPIRVInstruction *addUnaryInst(Op, SPIRVType *, SPIRVValue *, + SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addVariable(SPIRVType *, bool, SPIRVLinkageTypeKind, + SPIRVValue *, const std::string &, SPIRVStorageClassKind, SPIRVBasicBlock *) + = 0; + virtual SPIRVValue *addVectorShuffleInst(SPIRVType *Type, SPIRVValue *Vec1, + SPIRVValue *Vec2, const std::vector<SPIRVWord> &Components, + SPIRVBasicBlock *BB) = 0; + virtual SPIRVInstruction *addVectorExtractDynamicInst(SPIRVValue *, + SPIRVValue *, SPIRVBasicBlock *) = 0; + virtual SPIRVInstruction *addVectorInsertDynamicInst(SPIRVValue *, + SPIRVValue *, SPIRVValue*, SPIRVBasicBlock *) = 0; + // I/O functions + friend spv_ostream & operator<<(spv_ostream &O, SPIRVModule& M); + friend std::istream & operator>>(std::istream &I, SPIRVModule& M); +protected: + bool AutoAddCapability; + bool ValidateCapability; +}; + +class SPIRVDbgInfo { +public: + SPIRVDbgInfo(SPIRVModule *TM); + std::string getEntryPointFileStr(SPIRVExecutionModelKind, unsigned); + std::string getFunctionFileStr(SPIRVFunction *); + unsigned getFunctionLineNo(SPIRVFunction *); +private: + std::unordered_map<SPIRVFunction *, SPIRVLine *> FuncMap; + const std::string ModuleFileStr; + SPIRVModule *M; +}; + +#ifdef _SPIRV_SUPPORT_TEXT_FMT + +/// Convert SPIR-V between binary and internel text formats. +/// This function is not thread safe and should not be used in multi-thread +/// applications unless guarded by a critical section. +bool ConvertSPIRV(std::istream &IS, spv_ostream &OS, + std::string &ErrMsg, bool FromText, bool ToText); + +/// Convert SPIR-V between binary and internel text formats. +/// This function is not thread safe and should not be used in multi-thread +/// applications unless guarded by a critical section. +bool ConvertSPIRV(std::string &Input, std::string &Out, + std::string &ErrMsg, bool ToText); +#endif +} + + + +#endif /* SPIRVMODULE_HPP_ */ diff --git a/lib/SPIRV/libSPIRV/SPIRVOpCode.h b/lib/SPIRV/libSPIRV/SPIRVOpCode.h index f502fa2..5be96ab 100644 --- a/lib/SPIRV/libSPIRV/SPIRVOpCode.h +++ b/lib/SPIRV/libSPIRV/SPIRVOpCode.h @@ -1,178 +1,178 @@ -//===- SPIRVOpCode.h - Class to represent SPIR-V Operation Codes -*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines Operation Code class for SPIR-V.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVOPCODE_HPP_
-#define SPIRVOPCODE_HPP_
-
-#include "SPIRVUtil.h"
-#include "spirv.hpp"
-#include <string>
-
-using namespace spv;
-namespace SPIRV{
-
-template<> inline void
-SPIRVMap<Op, std::string>::init() {
-#define _SPIRV_OP(x, ...) add(Op##x, #x);
-#include "SPIRVOpCodeEnum.h"
-#undef _SPIRV_OP
-}
-SPIRV_DEF_NAMEMAP(Op, OpCodeNameMap)
-
-inline bool isAtomicOpCode(Op OpCode) {
- assert(OpAtomicLoad < OpAtomicXor);
- return ((unsigned)OpCode >= OpAtomicLoad
- && (unsigned)OpCode <= OpAtomicXor)
- || OpCode == OpAtomicFlagTestAndSet
- || OpCode == OpAtomicFlagClear;
-}
-inline bool isBinaryOpCode(Op OpCode) {
- return ((unsigned)OpCode >= OpIAdd &&
- (unsigned)OpCode <= OpFMod) ||
- OpCode == OpDot;
-}
-
-inline bool isShiftOpCode(Op OpCode) {
- return (unsigned)OpCode >= OpShiftRightLogical &&
- (unsigned)OpCode <= OpShiftLeftLogical;
-}
-
-inline bool isLogicalOpCode(Op OpCode) {
- return (unsigned)OpCode >= OpLogicalEqual &&
- (unsigned)OpCode <= OpLogicalNot;
-}
-
-inline bool isBitwiseOpCode(Op OpCode) {
- return (unsigned)OpCode >= OpBitwiseOr &&
- (unsigned)OpCode <= OpBitwiseAnd;
-}
-
-inline bool isBinaryShiftLogicalBitwiseOpCode(Op OpCode) {
- return (((unsigned)OpCode >= OpShiftRightLogical &&
- (unsigned)OpCode <= OpBitwiseAnd) ||
- isBinaryOpCode(OpCode));
-}
-
-inline bool isCmpOpCode(Op OpCode) {
- return ((unsigned)OpCode >= OpIEqual &&
- (unsigned)OpCode <= OpFUnordGreaterThanEqual) ||
- (OpCode >= OpLessOrGreater && OpCode <= OpLogicalNotEqual);
-}
-
-inline bool isCvtOpCode(Op OpCode) {
- return ((unsigned)OpCode >= OpConvertFToU &&
- (unsigned)OpCode <= OpBitcast) ||
- OpCode == OpSatConvertSToU ||
- OpCode == OpSatConvertUToS;
-}
-
-inline bool isCvtToUnsignedOpCode(Op OpCode) {
- return OpCode == OpConvertFToU ||
- OpCode == OpUConvert ||
- OpCode == OpSatConvertSToU;
-}
-
-inline bool isCvtFromUnsignedOpCode(Op OpCode) {
- return OpCode == OpConvertUToF ||
- OpCode == OpUConvert ||
- OpCode == OpSatConvertUToS;
-}
-
-inline bool isOpaqueGenericTypeOpCode(Op OpCode) {
- return (unsigned)OpCode >= OpTypeEvent &&
- (unsigned)OpCode <= OpTypeQueue;
-}
-
-inline bool isGenericNegateOpCode(Op OpCode) {
- return (unsigned)OpCode == OpSNegate ||
- (unsigned)OpCode == OpFNegate ||
- (unsigned)OpCode == OpNot;
-}
-
-inline bool isAccessChainOpCode(Op OpCode) {
- return OpCode == OpAccessChain ||
- OpCode == OpInBoundsAccessChain;
-}
-
-inline bool hasExecScope(Op OpCode) {
- unsigned OC = OpCode;
- return (OpGroupWaitEvents <= OC &&
- OC <= OpGroupSMax) ||
- (OpGroupReserveReadPipePackets <= OC &&
- OC <= OpGroupCommitWritePipe);
-}
-
-inline bool hasGroupOperation(Op OpCode) {
- unsigned OC = OpCode;
- return OpGroupIAdd <= OC && OC <= OpGroupSMax;
-}
-
-inline bool isGroupOpCode(Op OpCode) {
- unsigned OC = OpCode;
- return OpGroupAll <= OC && OC <= OpGroupSMax;
-}
-
-inline bool isPipeOpCode(Op OpCode) {
- unsigned OC = OpCode;
- return OpReadPipe <= OC && OC <= OpGroupCommitWritePipe;
-}
-inline bool isTypeOpCode(Op OpCode) {
- unsigned OC = OpCode;
- return (OpTypeVoid <= OC && OC <= OpTypePipe) || OC == OpTypePipeStorage;
-}
-
-inline bool isConstantOpCode(Op OpCode) {
- unsigned OC = OpCode;
- return (OpConstantTrue <= OC
- && OC <= OpSpecConstantOp)
- || OC == OpUndef || OC == OpConstantPipeStorage;
-}
-
-inline bool isModuleScopeAllowedOpCode(Op OpCode) {
- return OpCode == OpVariable ||
- isConstantOpCode(OpCode);
-}
-
-inline bool isIntelSubgroupOpCode(Op OpCode) {
- unsigned OC = OpCode;
- return OpSubgroupShuffleINTEL <= OC && OC <=OpSubgroupImageBlockWriteINTEL;
-}
-}
-
-#endif /* SPIRVOPCODE_HPP_ */
+//===- SPIRVOpCode.h - Class to represent SPIR-V Operation Codes -*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines Operation Code class for SPIR-V. +/// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVOPCODE_HPP_ +#define SPIRVOPCODE_HPP_ + +#include "SPIRVUtil.h" +#include "spirv.hpp" +#include <string> + +using namespace spv; +namespace SPIRV{ + +template<> inline void +SPIRVMap<Op, std::string>::init() { +#define _SPIRV_OP(x, ...) add(Op##x, #x); +#include "SPIRVOpCodeEnum.h" +#undef _SPIRV_OP +} +SPIRV_DEF_NAMEMAP(Op, OpCodeNameMap) + +inline bool isAtomicOpCode(Op OpCode) { + assert(OpAtomicLoad < OpAtomicXor); + return ((unsigned)OpCode >= OpAtomicLoad + && (unsigned)OpCode <= OpAtomicXor) + || OpCode == OpAtomicFlagTestAndSet + || OpCode == OpAtomicFlagClear; +} +inline bool isBinaryOpCode(Op OpCode) { + return ((unsigned)OpCode >= OpIAdd && + (unsigned)OpCode <= OpFMod) || + OpCode == OpDot; +} + +inline bool isShiftOpCode(Op OpCode) { + return (unsigned)OpCode >= OpShiftRightLogical && + (unsigned)OpCode <= OpShiftLeftLogical; +} + +inline bool isLogicalOpCode(Op OpCode) { + return (unsigned)OpCode >= OpLogicalEqual && + (unsigned)OpCode <= OpLogicalNot; +} + +inline bool isBitwiseOpCode(Op OpCode) { + return (unsigned)OpCode >= OpBitwiseOr && + (unsigned)OpCode <= OpBitwiseAnd; +} + +inline bool isBinaryShiftLogicalBitwiseOpCode(Op OpCode) { + return (((unsigned)OpCode >= OpShiftRightLogical && + (unsigned)OpCode <= OpBitwiseAnd) || + isBinaryOpCode(OpCode)); +} + +inline bool isCmpOpCode(Op OpCode) { + return ((unsigned)OpCode >= OpIEqual && + (unsigned)OpCode <= OpFUnordGreaterThanEqual) || + (OpCode >= OpLessOrGreater && OpCode <= OpLogicalNotEqual); +} + +inline bool isCvtOpCode(Op OpCode) { + return ((unsigned)OpCode >= OpConvertFToU && + (unsigned)OpCode <= OpBitcast) || + OpCode == OpSatConvertSToU || + OpCode == OpSatConvertUToS; +} + +inline bool isCvtToUnsignedOpCode(Op OpCode) { + return OpCode == OpConvertFToU || + OpCode == OpUConvert || + OpCode == OpSatConvertSToU; +} + +inline bool isCvtFromUnsignedOpCode(Op OpCode) { + return OpCode == OpConvertUToF || + OpCode == OpUConvert || + OpCode == OpSatConvertUToS; +} + +inline bool isOpaqueGenericTypeOpCode(Op OpCode) { + return (unsigned)OpCode >= OpTypeEvent && + (unsigned)OpCode <= OpTypeQueue; +} + +inline bool isGenericNegateOpCode(Op OpCode) { + return (unsigned)OpCode == OpSNegate || + (unsigned)OpCode == OpFNegate || + (unsigned)OpCode == OpNot; +} + +inline bool isAccessChainOpCode(Op OpCode) { + return OpCode == OpAccessChain || + OpCode == OpInBoundsAccessChain; +} + +inline bool hasExecScope(Op OpCode) { + unsigned OC = OpCode; + return (OpGroupWaitEvents <= OC && + OC <= OpGroupSMax) || + (OpGroupReserveReadPipePackets <= OC && + OC <= OpGroupCommitWritePipe); +} + +inline bool hasGroupOperation(Op OpCode) { + unsigned OC = OpCode; + return OpGroupIAdd <= OC && OC <= OpGroupSMax; +} + +inline bool isGroupOpCode(Op OpCode) { + unsigned OC = OpCode; + return OpGroupAll <= OC && OC <= OpGroupSMax; +} + +inline bool isPipeOpCode(Op OpCode) { + unsigned OC = OpCode; + return OpReadPipe <= OC && OC <= OpGroupCommitWritePipe; +} +inline bool isTypeOpCode(Op OpCode) { + unsigned OC = OpCode; + return (OpTypeVoid <= OC && OC <= OpTypePipe) || OC == OpTypePipeStorage; +} + +inline bool isConstantOpCode(Op OpCode) { + unsigned OC = OpCode; + return (OpConstantTrue <= OC + && OC <= OpSpecConstantOp) + || OC == OpUndef || OC == OpConstantPipeStorage; +} + +inline bool isModuleScopeAllowedOpCode(Op OpCode) { + return OpCode == OpVariable || + isConstantOpCode(OpCode); +} + +inline bool isIntelSubgroupOpCode(Op OpCode) { + unsigned OC = OpCode; + return OpSubgroupShuffleINTEL <= OC && OC <=OpSubgroupImageBlockWriteINTEL; +} +} + +#endif /* SPIRVOPCODE_HPP_ */ diff --git a/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h b/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h index bd81aba..f219a8a 100644 --- a/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h +++ b/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h @@ -1,300 +1,300 @@ -_SPIRV_OP(Nop, 0)
-_SPIRV_OP(Undef, 1)
-_SPIRV_OP(SourceContinued, 2)
-_SPIRV_OP(Source, 3)
-_SPIRV_OP(SourceExtension, 4)
-_SPIRV_OP(Name, 5)
-_SPIRV_OP(MemberName, 6)
-_SPIRV_OP(String, 7)
-_SPIRV_OP(Line, 8)
-_SPIRV_OP(Extension, 10)
-_SPIRV_OP(ExtInstImport, 11)
-_SPIRV_OP(ExtInst, 12)
-_SPIRV_OP(MemoryModel, 14)
-_SPIRV_OP(EntryPoint, 15)
-_SPIRV_OP(ExecutionMode, 16)
-_SPIRV_OP(Capability, 17)
-_SPIRV_OP(TypeVoid, 19)
-_SPIRV_OP(TypeBool, 20)
-_SPIRV_OP(TypeInt, 21)
-_SPIRV_OP(TypeFloat, 22)
-_SPIRV_OP(TypeVector, 23)
-_SPIRV_OP(TypeMatrix, 24)
-_SPIRV_OP(TypeImage, 25)
-_SPIRV_OP(TypeSampler, 26)
-_SPIRV_OP(TypeSampledImage, 27)
-_SPIRV_OP(TypeArray, 28)
-_SPIRV_OP(TypeRuntimeArray, 29)
-_SPIRV_OP(TypeStruct, 30)
-_SPIRV_OP(TypeOpaque, 31)
-_SPIRV_OP(TypePointer, 32)
-_SPIRV_OP(TypeFunction, 33)
-_SPIRV_OP(TypeEvent, 34)
-_SPIRV_OP(TypeDeviceEvent, 35)
-_SPIRV_OP(TypeReserveId, 36)
-_SPIRV_OP(TypeQueue, 37)
-_SPIRV_OP(TypePipe, 38)
-_SPIRV_OP(TypeForwardPointer, 39)
-_SPIRV_OP(ConstantTrue, 41)
-_SPIRV_OP(ConstantFalse, 42)
-_SPIRV_OP(Constant, 43)
-_SPIRV_OP(ConstantComposite, 44)
-_SPIRV_OP(ConstantSampler, 45)
-_SPIRV_OP(ConstantNull, 46)
-_SPIRV_OP(SpecConstantTrue, 48)
-_SPIRV_OP(SpecConstantFalse, 49)
-_SPIRV_OP(SpecConstant, 50)
-_SPIRV_OP(SpecConstantComposite, 51)
-_SPIRV_OP(SpecConstantOp, 52)
-_SPIRV_OP(Function, 54)
-_SPIRV_OP(FunctionParameter, 55)
-_SPIRV_OP(FunctionEnd, 56)
-_SPIRV_OP(FunctionCall, 57)
-_SPIRV_OP(Variable, 59)
-_SPIRV_OP(ImageTexelPointer, 60)
-_SPIRV_OP(Load, 61)
-_SPIRV_OP(Store, 62)
-_SPIRV_OP(CopyMemory, 63)
-_SPIRV_OP(CopyMemorySized, 64)
-_SPIRV_OP(AccessChain, 65)
-_SPIRV_OP(InBoundsAccessChain, 66)
-_SPIRV_OP(PtrAccessChain, 67)
-_SPIRV_OP(ArrayLength, 68)
-_SPIRV_OP(GenericPtrMemSemantics, 69)
-_SPIRV_OP(InBoundsPtrAccessChain, 70)
-_SPIRV_OP(Decorate, 71)
-_SPIRV_OP(MemberDecorate, 72)
-_SPIRV_OP(DecorationGroup, 73)
-_SPIRV_OP(GroupDecorate, 74)
-_SPIRV_OP(GroupMemberDecorate, 75)
-_SPIRV_OP(VectorExtractDynamic, 77)
-_SPIRV_OP(VectorInsertDynamic, 78)
-_SPIRV_OP(VectorShuffle, 79)
-_SPIRV_OP(CompositeConstruct, 80)
-_SPIRV_OP(CompositeExtract, 81)
-_SPIRV_OP(CompositeInsert, 82)
-_SPIRV_OP(CopyObject, 83)
-_SPIRV_OP(Transpose, 84)
-_SPIRV_OP(SampledImage, 86)
-_SPIRV_OP(ImageSampleImplicitLod, 87)
-_SPIRV_OP(ImageSampleExplicitLod, 88)
-_SPIRV_OP(ImageSampleDrefImplicitLod, 89)
-_SPIRV_OP(ImageSampleDrefExplicitLod, 90)
-_SPIRV_OP(ImageSampleProjImplicitLod, 91)
-_SPIRV_OP(ImageSampleProjExplicitLod, 92)
-_SPIRV_OP(ImageSampleProjDrefImplicitLod, 93)
-_SPIRV_OP(ImageSampleProjDrefExplicitLod, 94)
-_SPIRV_OP(ImageFetch, 95)
-_SPIRV_OP(ImageGather, 96)
-_SPIRV_OP(ImageDrefGather, 97)
-_SPIRV_OP(ImageRead, 98)
-_SPIRV_OP(ImageWrite, 99)
-_SPIRV_OP(Image, 100)
-_SPIRV_OP(ImageQueryFormat, 101)
-_SPIRV_OP(ImageQueryOrder, 102)
-_SPIRV_OP(ImageQuerySizeLod, 103)
-_SPIRV_OP(ImageQuerySize, 104)
-_SPIRV_OP(ImageQueryLod, 105)
-_SPIRV_OP(ImageQueryLevels, 106)
-_SPIRV_OP(ImageQuerySamples, 107)
-_SPIRV_OP(ConvertFToU, 109)
-_SPIRV_OP(ConvertFToS, 110)
-_SPIRV_OP(ConvertSToF, 111)
-_SPIRV_OP(ConvertUToF, 112)
-_SPIRV_OP(UConvert, 113)
-_SPIRV_OP(SConvert, 114)
-_SPIRV_OP(FConvert, 115)
-_SPIRV_OP(QuantizeToF16, 116)
-_SPIRV_OP(ConvertPtrToU, 117)
-_SPIRV_OP(SatConvertSToU, 118)
-_SPIRV_OP(SatConvertUToS, 119)
-_SPIRV_OP(ConvertUToPtr, 120)
-_SPIRV_OP(PtrCastToGeneric, 121)
-_SPIRV_OP(GenericCastToPtr, 122)
-_SPIRV_OP(GenericCastToPtrExplicit, 123)
-_SPIRV_OP(Bitcast, 124)
-_SPIRV_OP(SNegate, 126)
-_SPIRV_OP(FNegate, 127)
-_SPIRV_OP(IAdd, 128)
-_SPIRV_OP(FAdd, 129)
-_SPIRV_OP(ISub, 130)
-_SPIRV_OP(FSub, 131)
-_SPIRV_OP(IMul, 132)
-_SPIRV_OP(FMul, 133)
-_SPIRV_OP(UDiv, 134)
-_SPIRV_OP(SDiv, 135)
-_SPIRV_OP(FDiv, 136)
-_SPIRV_OP(UMod, 137)
-_SPIRV_OP(SRem, 138)
-_SPIRV_OP(SMod, 139)
-_SPIRV_OP(FRem, 140)
-_SPIRV_OP(FMod, 141)
-_SPIRV_OP(VectorTimesScalar, 142)
-_SPIRV_OP(MatrixTimesScalar, 143)
-_SPIRV_OP(VectorTimesMatrix, 144)
-_SPIRV_OP(MatrixTimesVector, 145)
-_SPIRV_OP(MatrixTimesMatrix, 146)
-_SPIRV_OP(OuterProduct, 147)
-_SPIRV_OP(Dot, 148)
-_SPIRV_OP(IAddCarry, 149)
-_SPIRV_OP(ISubBorrow, 150)
-_SPIRV_OP(UMulExtended, 151)
-_SPIRV_OP(SMulExtended, 152)
-_SPIRV_OP(Any, 154)
-_SPIRV_OP(All, 155)
-_SPIRV_OP(IsNan, 156)
-_SPIRV_OP(IsInf, 157)
-_SPIRV_OP(IsFinite, 158)
-_SPIRV_OP(IsNormal, 159)
-_SPIRV_OP(SignBitSet, 160)
-_SPIRV_OP(LessOrGreater, 161)
-_SPIRV_OP(Ordered, 162)
-_SPIRV_OP(Unordered, 163)
-_SPIRV_OP(LogicalEqual, 164)
-_SPIRV_OP(LogicalNotEqual, 165)
-_SPIRV_OP(LogicalOr, 166)
-_SPIRV_OP(LogicalAnd, 167)
-_SPIRV_OP(LogicalNot, 168)
-_SPIRV_OP(Select, 169)
-_SPIRV_OP(IEqual, 170)
-_SPIRV_OP(INotEqual, 171)
-_SPIRV_OP(UGreaterThan, 172)
-_SPIRV_OP(SGreaterThan, 173)
-_SPIRV_OP(UGreaterThanEqual, 174)
-_SPIRV_OP(SGreaterThanEqual, 175)
-_SPIRV_OP(ULessThan, 176)
-_SPIRV_OP(SLessThan, 177)
-_SPIRV_OP(ULessThanEqual, 178)
-_SPIRV_OP(SLessThanEqual, 179)
-_SPIRV_OP(FOrdEqual, 180)
-_SPIRV_OP(FUnordEqual, 181)
-_SPIRV_OP(FOrdNotEqual, 182)
-_SPIRV_OP(FUnordNotEqual, 183)
-_SPIRV_OP(FOrdLessThan, 184)
-_SPIRV_OP(FUnordLessThan, 185)
-_SPIRV_OP(FOrdGreaterThan, 186)
-_SPIRV_OP(FUnordGreaterThan, 187)
-_SPIRV_OP(FOrdLessThanEqual, 188)
-_SPIRV_OP(FUnordLessThanEqual, 189)
-_SPIRV_OP(FOrdGreaterThanEqual, 190)
-_SPIRV_OP(FUnordGreaterThanEqual, 191)
-_SPIRV_OP(ShiftRightLogical, 194)
-_SPIRV_OP(ShiftRightArithmetic, 195)
-_SPIRV_OP(ShiftLeftLogical, 196)
-_SPIRV_OP(BitwiseOr, 197)
-_SPIRV_OP(BitwiseXor, 198)
-_SPIRV_OP(BitwiseAnd, 199)
-_SPIRV_OP(Not, 200)
-_SPIRV_OP(BitFieldInsert, 201)
-_SPIRV_OP(BitFieldSExtract, 202)
-_SPIRV_OP(BitFieldUExtract, 203)
-_SPIRV_OP(BitReverse, 204)
-_SPIRV_OP(BitCount, 205)
-_SPIRV_OP(DPdx, 207)
-_SPIRV_OP(DPdy, 208)
-_SPIRV_OP(Fwidth, 209)
-_SPIRV_OP(DPdxFine, 210)
-_SPIRV_OP(DPdyFine, 211)
-_SPIRV_OP(FwidthFine, 212)
-_SPIRV_OP(DPdxCoarse, 213)
-_SPIRV_OP(DPdyCoarse, 214)
-_SPIRV_OP(FwidthCoarse, 215)
-_SPIRV_OP(EmitVertex, 218)
-_SPIRV_OP(EndPrimitive, 219)
-_SPIRV_OP(EmitStreamVertex, 220)
-_SPIRV_OP(EndStreamPrimitive, 221)
-_SPIRV_OP(ControlBarrier, 224)
-_SPIRV_OP(MemoryBarrier, 225)
-_SPIRV_OP(AtomicLoad, 227)
-_SPIRV_OP(AtomicStore, 228)
-_SPIRV_OP(AtomicExchange, 229)
-_SPIRV_OP(AtomicCompareExchange, 230)
-_SPIRV_OP(AtomicCompareExchangeWeak, 231)
-_SPIRV_OP(AtomicIIncrement, 232)
-_SPIRV_OP(AtomicIDecrement, 233)
-_SPIRV_OP(AtomicIAdd, 234)
-_SPIRV_OP(AtomicISub, 235)
-_SPIRV_OP(AtomicSMin, 236)
-_SPIRV_OP(AtomicUMin, 237)
-_SPIRV_OP(AtomicSMax, 238)
-_SPIRV_OP(AtomicUMax, 239)
-_SPIRV_OP(AtomicAnd, 240)
-_SPIRV_OP(AtomicOr, 241)
-_SPIRV_OP(AtomicXor, 242)
-_SPIRV_OP(Phi, 245)
-_SPIRV_OP(LoopMerge, 246)
-_SPIRV_OP(SelectionMerge, 247)
-_SPIRV_OP(Label, 248)
-_SPIRV_OP(Branch, 249)
-_SPIRV_OP(BranchConditional, 250)
-_SPIRV_OP(Switch, 251)
-_SPIRV_OP(Kill, 252)
-_SPIRV_OP(Return, 253)
-_SPIRV_OP(ReturnValue, 254)
-_SPIRV_OP(Unreachable, 255)
-_SPIRV_OP(LifetimeStart, 256)
-_SPIRV_OP(LifetimeStop, 257)
-_SPIRV_OP(GroupAsyncCopy, 259)
-_SPIRV_OP(GroupWaitEvents, 260)
-_SPIRV_OP(GroupAll, 261)
-_SPIRV_OP(GroupAny, 262)
-_SPIRV_OP(GroupBroadcast, 263)
-_SPIRV_OP(GroupIAdd, 264)
-_SPIRV_OP(GroupFAdd, 265)
-_SPIRV_OP(GroupFMin, 266)
-_SPIRV_OP(GroupUMin, 267)
-_SPIRV_OP(GroupSMin, 268)
-_SPIRV_OP(GroupFMax, 269)
-_SPIRV_OP(GroupUMax, 270)
-_SPIRV_OP(GroupSMax, 271)
-_SPIRV_OP(ReadPipe, 274)
-_SPIRV_OP(WritePipe, 275)
-_SPIRV_OP(ReservedReadPipe, 276)
-_SPIRV_OP(ReservedWritePipe, 277)
-_SPIRV_OP(ReserveReadPipePackets, 278)
-_SPIRV_OP(ReserveWritePipePackets, 279)
-_SPIRV_OP(CommitReadPipe, 280)
-_SPIRV_OP(CommitWritePipe, 281)
-_SPIRV_OP(IsValidReserveId, 282)
-_SPIRV_OP(GetNumPipePackets, 283)
-_SPIRV_OP(GetMaxPipePackets, 284)
-_SPIRV_OP(GroupReserveReadPipePackets, 285)
-_SPIRV_OP(GroupReserveWritePipePackets, 286)
-_SPIRV_OP(GroupCommitReadPipe, 287)
-_SPIRV_OP(GroupCommitWritePipe, 288)
-_SPIRV_OP(EnqueueMarker, 291)
-_SPIRV_OP(EnqueueKernel, 292)
-_SPIRV_OP(GetKernelNDrangeSubGroupCount, 293)
-_SPIRV_OP(GetKernelNDrangeMaxSubGroupSize, 294)
-_SPIRV_OP(GetKernelWorkGroupSize, 295)
-_SPIRV_OP(GetKernelPreferredWorkGroupSizeMultiple, 296)
-_SPIRV_OP(RetainEvent, 297)
-_SPIRV_OP(ReleaseEvent, 298)
-_SPIRV_OP(CreateUserEvent, 299)
-_SPIRV_OP(IsValidEvent, 300)
-_SPIRV_OP(SetUserEventStatus, 301)
-_SPIRV_OP(CaptureEventProfilingInfo, 302)
-_SPIRV_OP(GetDefaultQueue, 303)
-_SPIRV_OP(BuildNDRange, 304)
-_SPIRV_OP(ImageSparseSampleImplicitLod, 305)
-_SPIRV_OP(ImageSparseSampleExplicitLod, 306)
-_SPIRV_OP(ImageSparseSampleDrefImplicitLod, 307)
-_SPIRV_OP(ImageSparseSampleDrefExplicitLod, 308)
-_SPIRV_OP(ImageSparseSampleProjImplicitLod, 309)
-_SPIRV_OP(ImageSparseSampleProjExplicitLod, 310)
-_SPIRV_OP(ImageSparseSampleProjDrefImplicitLod, 311)
-_SPIRV_OP(ImageSparseSampleProjDrefExplicitLod, 312)
-_SPIRV_OP(ImageSparseFetch, 313)
-_SPIRV_OP(ImageSparseGather, 314)
-_SPIRV_OP(ImageSparseDrefGather, 315)
-_SPIRV_OP(ImageSparseTexelsResident, 316)
-_SPIRV_OP(NoLine, 317)
-_SPIRV_OP(AtomicFlagTestAndSet, 318)
-_SPIRV_OP(AtomicFlagClear, 319)
-_SPIRV_OP(TypePipeStorage, 322)
-_SPIRV_OP(ConstantPipeStorage, 323)
-_SPIRV_OP(CreatePipeFromPipeStorage, 324)
-_SPIRV_OP(Forward, 1024)
+_SPIRV_OP(Nop, 0) +_SPIRV_OP(Undef, 1) +_SPIRV_OP(SourceContinued, 2) +_SPIRV_OP(Source, 3) +_SPIRV_OP(SourceExtension, 4) +_SPIRV_OP(Name, 5) +_SPIRV_OP(MemberName, 6) +_SPIRV_OP(String, 7) +_SPIRV_OP(Line, 8) +_SPIRV_OP(Extension, 10) +_SPIRV_OP(ExtInstImport, 11) +_SPIRV_OP(ExtInst, 12) +_SPIRV_OP(MemoryModel, 14) +_SPIRV_OP(EntryPoint, 15) +_SPIRV_OP(ExecutionMode, 16) +_SPIRV_OP(Capability, 17) +_SPIRV_OP(TypeVoid, 19) +_SPIRV_OP(TypeBool, 20) +_SPIRV_OP(TypeInt, 21) +_SPIRV_OP(TypeFloat, 22) +_SPIRV_OP(TypeVector, 23) +_SPIRV_OP(TypeMatrix, 24) +_SPIRV_OP(TypeImage, 25) +_SPIRV_OP(TypeSampler, 26) +_SPIRV_OP(TypeSampledImage, 27) +_SPIRV_OP(TypeArray, 28) +_SPIRV_OP(TypeRuntimeArray, 29) +_SPIRV_OP(TypeStruct, 30) +_SPIRV_OP(TypeOpaque, 31) +_SPIRV_OP(TypePointer, 32) +_SPIRV_OP(TypeFunction, 33) +_SPIRV_OP(TypeEvent, 34) +_SPIRV_OP(TypeDeviceEvent, 35) +_SPIRV_OP(TypeReserveId, 36) +_SPIRV_OP(TypeQueue, 37) +_SPIRV_OP(TypePipe, 38) +_SPIRV_OP(TypeForwardPointer, 39) +_SPIRV_OP(ConstantTrue, 41) +_SPIRV_OP(ConstantFalse, 42) +_SPIRV_OP(Constant, 43) +_SPIRV_OP(ConstantComposite, 44) +_SPIRV_OP(ConstantSampler, 45) +_SPIRV_OP(ConstantNull, 46) +_SPIRV_OP(SpecConstantTrue, 48) +_SPIRV_OP(SpecConstantFalse, 49) +_SPIRV_OP(SpecConstant, 50) +_SPIRV_OP(SpecConstantComposite, 51) +_SPIRV_OP(SpecConstantOp, 52) +_SPIRV_OP(Function, 54) +_SPIRV_OP(FunctionParameter, 55) +_SPIRV_OP(FunctionEnd, 56) +_SPIRV_OP(FunctionCall, 57) +_SPIRV_OP(Variable, 59) +_SPIRV_OP(ImageTexelPointer, 60) +_SPIRV_OP(Load, 61) +_SPIRV_OP(Store, 62) +_SPIRV_OP(CopyMemory, 63) +_SPIRV_OP(CopyMemorySized, 64) +_SPIRV_OP(AccessChain, 65) +_SPIRV_OP(InBoundsAccessChain, 66) +_SPIRV_OP(PtrAccessChain, 67) +_SPIRV_OP(ArrayLength, 68) +_SPIRV_OP(GenericPtrMemSemantics, 69) +_SPIRV_OP(InBoundsPtrAccessChain, 70) +_SPIRV_OP(Decorate, 71) +_SPIRV_OP(MemberDecorate, 72) +_SPIRV_OP(DecorationGroup, 73) +_SPIRV_OP(GroupDecorate, 74) +_SPIRV_OP(GroupMemberDecorate, 75) +_SPIRV_OP(VectorExtractDynamic, 77) +_SPIRV_OP(VectorInsertDynamic, 78) +_SPIRV_OP(VectorShuffle, 79) +_SPIRV_OP(CompositeConstruct, 80) +_SPIRV_OP(CompositeExtract, 81) +_SPIRV_OP(CompositeInsert, 82) +_SPIRV_OP(CopyObject, 83) +_SPIRV_OP(Transpose, 84) +_SPIRV_OP(SampledImage, 86) +_SPIRV_OP(ImageSampleImplicitLod, 87) +_SPIRV_OP(ImageSampleExplicitLod, 88) +_SPIRV_OP(ImageSampleDrefImplicitLod, 89) +_SPIRV_OP(ImageSampleDrefExplicitLod, 90) +_SPIRV_OP(ImageSampleProjImplicitLod, 91) +_SPIRV_OP(ImageSampleProjExplicitLod, 92) +_SPIRV_OP(ImageSampleProjDrefImplicitLod, 93) +_SPIRV_OP(ImageSampleProjDrefExplicitLod, 94) +_SPIRV_OP(ImageFetch, 95) +_SPIRV_OP(ImageGather, 96) +_SPIRV_OP(ImageDrefGather, 97) +_SPIRV_OP(ImageRead, 98) +_SPIRV_OP(ImageWrite, 99) +_SPIRV_OP(Image, 100) +_SPIRV_OP(ImageQueryFormat, 101) +_SPIRV_OP(ImageQueryOrder, 102) +_SPIRV_OP(ImageQuerySizeLod, 103) +_SPIRV_OP(ImageQuerySize, 104) +_SPIRV_OP(ImageQueryLod, 105) +_SPIRV_OP(ImageQueryLevels, 106) +_SPIRV_OP(ImageQuerySamples, 107) +_SPIRV_OP(ConvertFToU, 109) +_SPIRV_OP(ConvertFToS, 110) +_SPIRV_OP(ConvertSToF, 111) +_SPIRV_OP(ConvertUToF, 112) +_SPIRV_OP(UConvert, 113) +_SPIRV_OP(SConvert, 114) +_SPIRV_OP(FConvert, 115) +_SPIRV_OP(QuantizeToF16, 116) +_SPIRV_OP(ConvertPtrToU, 117) +_SPIRV_OP(SatConvertSToU, 118) +_SPIRV_OP(SatConvertUToS, 119) +_SPIRV_OP(ConvertUToPtr, 120) +_SPIRV_OP(PtrCastToGeneric, 121) +_SPIRV_OP(GenericCastToPtr, 122) +_SPIRV_OP(GenericCastToPtrExplicit, 123) +_SPIRV_OP(Bitcast, 124) +_SPIRV_OP(SNegate, 126) +_SPIRV_OP(FNegate, 127) +_SPIRV_OP(IAdd, 128) +_SPIRV_OP(FAdd, 129) +_SPIRV_OP(ISub, 130) +_SPIRV_OP(FSub, 131) +_SPIRV_OP(IMul, 132) +_SPIRV_OP(FMul, 133) +_SPIRV_OP(UDiv, 134) +_SPIRV_OP(SDiv, 135) +_SPIRV_OP(FDiv, 136) +_SPIRV_OP(UMod, 137) +_SPIRV_OP(SRem, 138) +_SPIRV_OP(SMod, 139) +_SPIRV_OP(FRem, 140) +_SPIRV_OP(FMod, 141) +_SPIRV_OP(VectorTimesScalar, 142) +_SPIRV_OP(MatrixTimesScalar, 143) +_SPIRV_OP(VectorTimesMatrix, 144) +_SPIRV_OP(MatrixTimesVector, 145) +_SPIRV_OP(MatrixTimesMatrix, 146) +_SPIRV_OP(OuterProduct, 147) +_SPIRV_OP(Dot, 148) +_SPIRV_OP(IAddCarry, 149) +_SPIRV_OP(ISubBorrow, 150) +_SPIRV_OP(UMulExtended, 151) +_SPIRV_OP(SMulExtended, 152) +_SPIRV_OP(Any, 154) +_SPIRV_OP(All, 155) +_SPIRV_OP(IsNan, 156) +_SPIRV_OP(IsInf, 157) +_SPIRV_OP(IsFinite, 158) +_SPIRV_OP(IsNormal, 159) +_SPIRV_OP(SignBitSet, 160) +_SPIRV_OP(LessOrGreater, 161) +_SPIRV_OP(Ordered, 162) +_SPIRV_OP(Unordered, 163) +_SPIRV_OP(LogicalEqual, 164) +_SPIRV_OP(LogicalNotEqual, 165) +_SPIRV_OP(LogicalOr, 166) +_SPIRV_OP(LogicalAnd, 167) +_SPIRV_OP(LogicalNot, 168) +_SPIRV_OP(Select, 169) +_SPIRV_OP(IEqual, 170) +_SPIRV_OP(INotEqual, 171) +_SPIRV_OP(UGreaterThan, 172) +_SPIRV_OP(SGreaterThan, 173) +_SPIRV_OP(UGreaterThanEqual, 174) +_SPIRV_OP(SGreaterThanEqual, 175) +_SPIRV_OP(ULessThan, 176) +_SPIRV_OP(SLessThan, 177) +_SPIRV_OP(ULessThanEqual, 178) +_SPIRV_OP(SLessThanEqual, 179) +_SPIRV_OP(FOrdEqual, 180) +_SPIRV_OP(FUnordEqual, 181) +_SPIRV_OP(FOrdNotEqual, 182) +_SPIRV_OP(FUnordNotEqual, 183) +_SPIRV_OP(FOrdLessThan, 184) +_SPIRV_OP(FUnordLessThan, 185) +_SPIRV_OP(FOrdGreaterThan, 186) +_SPIRV_OP(FUnordGreaterThan, 187) +_SPIRV_OP(FOrdLessThanEqual, 188) +_SPIRV_OP(FUnordLessThanEqual, 189) +_SPIRV_OP(FOrdGreaterThanEqual, 190) +_SPIRV_OP(FUnordGreaterThanEqual, 191) +_SPIRV_OP(ShiftRightLogical, 194) +_SPIRV_OP(ShiftRightArithmetic, 195) +_SPIRV_OP(ShiftLeftLogical, 196) +_SPIRV_OP(BitwiseOr, 197) +_SPIRV_OP(BitwiseXor, 198) +_SPIRV_OP(BitwiseAnd, 199) +_SPIRV_OP(Not, 200) +_SPIRV_OP(BitFieldInsert, 201) +_SPIRV_OP(BitFieldSExtract, 202) +_SPIRV_OP(BitFieldUExtract, 203) +_SPIRV_OP(BitReverse, 204) +_SPIRV_OP(BitCount, 205) +_SPIRV_OP(DPdx, 207) +_SPIRV_OP(DPdy, 208) +_SPIRV_OP(Fwidth, 209) +_SPIRV_OP(DPdxFine, 210) +_SPIRV_OP(DPdyFine, 211) +_SPIRV_OP(FwidthFine, 212) +_SPIRV_OP(DPdxCoarse, 213) +_SPIRV_OP(DPdyCoarse, 214) +_SPIRV_OP(FwidthCoarse, 215) +_SPIRV_OP(EmitVertex, 218) +_SPIRV_OP(EndPrimitive, 219) +_SPIRV_OP(EmitStreamVertex, 220) +_SPIRV_OP(EndStreamPrimitive, 221) +_SPIRV_OP(ControlBarrier, 224) +_SPIRV_OP(MemoryBarrier, 225) +_SPIRV_OP(AtomicLoad, 227) +_SPIRV_OP(AtomicStore, 228) +_SPIRV_OP(AtomicExchange, 229) +_SPIRV_OP(AtomicCompareExchange, 230) +_SPIRV_OP(AtomicCompareExchangeWeak, 231) +_SPIRV_OP(AtomicIIncrement, 232) +_SPIRV_OP(AtomicIDecrement, 233) +_SPIRV_OP(AtomicIAdd, 234) +_SPIRV_OP(AtomicISub, 235) +_SPIRV_OP(AtomicSMin, 236) +_SPIRV_OP(AtomicUMin, 237) +_SPIRV_OP(AtomicSMax, 238) +_SPIRV_OP(AtomicUMax, 239) +_SPIRV_OP(AtomicAnd, 240) +_SPIRV_OP(AtomicOr, 241) +_SPIRV_OP(AtomicXor, 242) +_SPIRV_OP(Phi, 245) +_SPIRV_OP(LoopMerge, 246) +_SPIRV_OP(SelectionMerge, 247) +_SPIRV_OP(Label, 248) +_SPIRV_OP(Branch, 249) +_SPIRV_OP(BranchConditional, 250) +_SPIRV_OP(Switch, 251) +_SPIRV_OP(Kill, 252) +_SPIRV_OP(Return, 253) +_SPIRV_OP(ReturnValue, 254) +_SPIRV_OP(Unreachable, 255) +_SPIRV_OP(LifetimeStart, 256) +_SPIRV_OP(LifetimeStop, 257) +_SPIRV_OP(GroupAsyncCopy, 259) +_SPIRV_OP(GroupWaitEvents, 260) +_SPIRV_OP(GroupAll, 261) +_SPIRV_OP(GroupAny, 262) +_SPIRV_OP(GroupBroadcast, 263) +_SPIRV_OP(GroupIAdd, 264) +_SPIRV_OP(GroupFAdd, 265) +_SPIRV_OP(GroupFMin, 266) +_SPIRV_OP(GroupUMin, 267) +_SPIRV_OP(GroupSMin, 268) +_SPIRV_OP(GroupFMax, 269) +_SPIRV_OP(GroupUMax, 270) +_SPIRV_OP(GroupSMax, 271) +_SPIRV_OP(ReadPipe, 274) +_SPIRV_OP(WritePipe, 275) +_SPIRV_OP(ReservedReadPipe, 276) +_SPIRV_OP(ReservedWritePipe, 277) +_SPIRV_OP(ReserveReadPipePackets, 278) +_SPIRV_OP(ReserveWritePipePackets, 279) +_SPIRV_OP(CommitReadPipe, 280) +_SPIRV_OP(CommitWritePipe, 281) +_SPIRV_OP(IsValidReserveId, 282) +_SPIRV_OP(GetNumPipePackets, 283) +_SPIRV_OP(GetMaxPipePackets, 284) +_SPIRV_OP(GroupReserveReadPipePackets, 285) +_SPIRV_OP(GroupReserveWritePipePackets, 286) +_SPIRV_OP(GroupCommitReadPipe, 287) +_SPIRV_OP(GroupCommitWritePipe, 288) +_SPIRV_OP(EnqueueMarker, 291) +_SPIRV_OP(EnqueueKernel, 292) +_SPIRV_OP(GetKernelNDrangeSubGroupCount, 293) +_SPIRV_OP(GetKernelNDrangeMaxSubGroupSize, 294) +_SPIRV_OP(GetKernelWorkGroupSize, 295) +_SPIRV_OP(GetKernelPreferredWorkGroupSizeMultiple, 296) +_SPIRV_OP(RetainEvent, 297) +_SPIRV_OP(ReleaseEvent, 298) +_SPIRV_OP(CreateUserEvent, 299) +_SPIRV_OP(IsValidEvent, 300) +_SPIRV_OP(SetUserEventStatus, 301) +_SPIRV_OP(CaptureEventProfilingInfo, 302) +_SPIRV_OP(GetDefaultQueue, 303) +_SPIRV_OP(BuildNDRange, 304) +_SPIRV_OP(ImageSparseSampleImplicitLod, 305) +_SPIRV_OP(ImageSparseSampleExplicitLod, 306) +_SPIRV_OP(ImageSparseSampleDrefImplicitLod, 307) +_SPIRV_OP(ImageSparseSampleDrefExplicitLod, 308) +_SPIRV_OP(ImageSparseSampleProjImplicitLod, 309) +_SPIRV_OP(ImageSparseSampleProjExplicitLod, 310) +_SPIRV_OP(ImageSparseSampleProjDrefImplicitLod, 311) +_SPIRV_OP(ImageSparseSampleProjDrefExplicitLod, 312) +_SPIRV_OP(ImageSparseFetch, 313) +_SPIRV_OP(ImageSparseGather, 314) +_SPIRV_OP(ImageSparseDrefGather, 315) +_SPIRV_OP(ImageSparseTexelsResident, 316) +_SPIRV_OP(NoLine, 317) +_SPIRV_OP(AtomicFlagTestAndSet, 318) +_SPIRV_OP(AtomicFlagClear, 319) +_SPIRV_OP(TypePipeStorage, 322) +_SPIRV_OP(ConstantPipeStorage, 323) +_SPIRV_OP(CreatePipeFromPipeStorage, 324) +_SPIRV_OP(Forward, 1024) _SPIRV_OP(SubgroupShuffleINTEL, 5571) _SPIRV_OP(SubgroupShuffleDownINTEL, 5572) _SPIRV_OP(SubgroupShuffleUpINTEL, 5573) diff --git a/lib/SPIRV/libSPIRV/SPIRVStream.cpp b/lib/SPIRV/libSPIRV/SPIRVStream.cpp index 096d49b..5262e68 100644 --- a/lib/SPIRV/libSPIRV/SPIRVStream.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVStream.cpp @@ -1,270 +1,270 @@ -//===- SPIRVStream.cpp - Class to represent a SPIR-V Stream ------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file implements SPIR-V stream class.
-///
-//===----------------------------------------------------------------------===//
-#include "SPIRVDebug.h"
-#include "SPIRVStream.h"
-#include "SPIRVFunction.h"
-#include "SPIRVOpCode.h"
-#include "SPIRVNameMapEnum.h"
-
-namespace SPIRV{
-
-/// Write string with quote. Replace " with \".
-static void writeQuotedString(spv_ostream& O, const std::string& Str) {
- O << '"';
- for (auto I : Str) {
- if (I == '"')
- O << '\\';
- O << I;
- }
- O << '"';
-}
-
-/// Read quoted string. Replace \" with ".
-static void readQuotedString(std::istream &IS, std::string& Str) {
- char Ch = ' ';
- char PreCh = ' ';
- while (IS >> Ch && Ch != '"')
- ;
-
- if (IS >> PreCh && PreCh != '"') {
- while (IS >> Ch) {
- if (Ch == '"') {
- if (PreCh != '\\') {
- Str += PreCh;
- break;
- }
- else
- PreCh = Ch;
- } else {
- Str += PreCh;
- PreCh = Ch;
- }
- }
- }
-}
-
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
-bool SPIRVUseTextFormat = false;
-#endif
-
-SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVFunction &F)
- :IS(InputStream), M(*F.getModule()), WordCount(0), OpCode(OpNop),
- Scope(&F){}
-
-SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVBasicBlock &BB)
- :IS(InputStream), M(*BB.getModule()), WordCount(0), OpCode(OpNop),
- Scope(&BB){}
-
-void
-SPIRVDecoder::setScope(SPIRVEntry *TheScope) {
- assert(TheScope && (TheScope->getOpCode() == OpFunction ||
- TheScope->getOpCode() == OpLabel));
- Scope = TheScope;
-}
-
-template<class T>
-const SPIRVDecoder&
-decode(const SPIRVDecoder& I, T &V) {
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
- if (SPIRVUseTextFormat) {
- std::string W;
- I.IS >> W;
- V = getNameMap(V).rmap(W);
- SPIRVDBG(spvdbgs() << "Read word: W = " << W << " V = " << V << '\n');
- return I;
- }
-#endif
- return DecodeBinary(I, V);
-}
-
-template<class T>
-const SPIRVEncoder&
-encode(const SPIRVEncoder& O, T V) {
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
- if (SPIRVUseTextFormat) {
- O.OS << getNameMap(V).map(V) << " ";
- return O;
- }
-#endif
- return O << static_cast<SPIRVWord>(V);
-}
-
-#define SPIRV_DEF_ENCDEC(Type) \
-const SPIRVDecoder& \
-operator>>(const SPIRVDecoder& I, Type &V) { \
- return decode(I, V); \
-}\
-const SPIRVEncoder& \
-operator<<(const SPIRVEncoder& O, Type V) { \
- return encode(O, V); \
-}
-
-SPIRV_DEF_ENCDEC(Op)
-SPIRV_DEF_ENCDEC(Capability)
-SPIRV_DEF_ENCDEC(Decoration)
-SPIRV_DEF_ENCDEC(OCLExtOpKind)
-SPIRV_DEF_ENCDEC(LinkageType)
-
-// Read a string with padded 0's at the end so that they form a stream of
-// words.
-const SPIRVDecoder&
-operator>>(const SPIRVDecoder&I, std::string& Str) {
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
- if (SPIRVUseTextFormat) {
- readQuotedString(I.IS, Str);
- SPIRVDBG(spvdbgs() << "Read string: \"" << Str << "\"\n");
- return I;
- }
-#endif
-
- uint64_t Count = 0;
- char Ch;
- while (I.IS.get(Ch) && Ch != '\0') {
- Str += Ch;
- ++Count;
- }
- Count = (Count + 1) % 4;
- Count = Count ? 4 - Count : 0;
- for (;Count; --Count) {
- I.IS >> Ch;
- assert(Ch == '\0' && "Invalid string in SPIRV");
- }
- SPIRVDBG(spvdbgs() << "Read string: \"" << Str << "\"\n");
- return I;
-}
-
-// Write a string with padded 0's at the end so that they form a stream of
-// words.
-const SPIRVEncoder&
-operator<<(const SPIRVEncoder&O, const std::string& Str) {
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
- if (SPIRVUseTextFormat) {
- writeQuotedString(O.OS, Str);
- return O;
- }
-#endif
-
- size_t L = Str.length();
- O.OS.write(Str.c_str(), L);
- char Zeros[4] = {0, 0, 0, 0};
- O.OS.write(Zeros, 4-L%4);
- return O;
-}
-
-bool
-SPIRVDecoder::getWordCountAndOpCode() {
- if (IS.eof()) {
- WordCount = 0;
- OpCode = OpNop;
- SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode EOF " <<
- WordCount << " " << OpCode << '\n');
- return false;
- }
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
- if (SPIRVUseTextFormat) {
- *this >> WordCount;
- assert(!IS.bad() && "SPIRV stream is bad");
- if (IS.fail()) {
- WordCount = 0;
- OpCode = OpNop;
- SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode FAIL " <<
- WordCount << " " << OpCode << '\n');
- return false;
- }
- *this >> OpCode;
- } else {
-#endif
- SPIRVWord WordCountAndOpCode;
- *this >> WordCountAndOpCode;
- WordCount = WordCountAndOpCode >> 16;
- OpCode = static_cast<Op>(WordCountAndOpCode & 0xFFFF);
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
- }
-#endif
- assert(!IS.bad() && "SPIRV stream is bad");
- if (IS.fail()) {
- WordCount = 0;
- OpCode = OpNop;
- SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode FAIL " <<
- WordCount << " " << OpCode << '\n');
- return false;
- }
- SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode " << WordCount <<
- " " << OpCodeNameMap::map(OpCode) << '\n');
- return true;
-}
-
-SPIRVEntry *
-SPIRVDecoder::getEntry() {
- if (WordCount == 0 || OpCode == OpNop)
- return nullptr;
- SPIRVEntry *Entry = SPIRVEntry::create(OpCode);
- assert(Entry);
- Entry->setModule(&M);
- if (isModuleScopeAllowedOpCode(OpCode) && !Scope) {}
- else
- Entry->setScope(Scope);
- Entry->setWordCount(WordCount);
- if (OpCode != OpLine)
- Entry->setLine(M.getCurrentLine());
- IS >> *Entry;
- if (Entry->isEndOfBlock() || OpCode == OpNoLine)
- M.setCurrentLine(nullptr);
- assert(!IS.bad() && !IS.fail() && "SPIRV stream fails");
- return Entry;
-}
-
-void
-SPIRVDecoder::validate()const {
- assert(OpCode != OpNop && "Invalid op code");
- assert(WordCount && "Invalid word count");
- assert(!IS.bad() && "Bad iInput stream");
-}
-
-spv_ostream &
-operator<<(spv_ostream &O, const SPIRVNL &E) {
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
- if (SPIRVUseTextFormat)
- O << '\n';
-#endif
- return O;
-}
-
-} // end of SPIRV namespace
-
+//===- SPIRVStream.cpp - Class to represent a SPIR-V Stream ------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file implements SPIR-V stream class. +/// +//===----------------------------------------------------------------------===// +#include "SPIRVDebug.h" +#include "SPIRVStream.h" +#include "SPIRVFunction.h" +#include "SPIRVOpCode.h" +#include "SPIRVNameMapEnum.h" + +namespace SPIRV{ + +/// Write string with quote. Replace " with \". +static void writeQuotedString(spv_ostream& O, const std::string& Str) { + O << '"'; + for (auto I : Str) { + if (I == '"') + O << '\\'; + O << I; + } + O << '"'; +} + +/// Read quoted string. Replace \" with ". +static void readQuotedString(std::istream &IS, std::string& Str) { + char Ch = ' '; + char PreCh = ' '; + while (IS >> Ch && Ch != '"') + ; + + if (IS >> PreCh && PreCh != '"') { + while (IS >> Ch) { + if (Ch == '"') { + if (PreCh != '\\') { + Str += PreCh; + break; + } + else + PreCh = Ch; + } else { + Str += PreCh; + PreCh = Ch; + } + } + } +} + +#ifdef _SPIRV_SUPPORT_TEXT_FMT +bool SPIRVUseTextFormat = false; +#endif + +SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVFunction &F) + :IS(InputStream), M(*F.getModule()), WordCount(0), OpCode(OpNop), + Scope(&F){} + +SPIRVDecoder::SPIRVDecoder(std::istream &InputStream, SPIRVBasicBlock &BB) + :IS(InputStream), M(*BB.getModule()), WordCount(0), OpCode(OpNop), + Scope(&BB){} + +void +SPIRVDecoder::setScope(SPIRVEntry *TheScope) { + assert(TheScope && (TheScope->getOpCode() == OpFunction || + TheScope->getOpCode() == OpLabel)); + Scope = TheScope; +} + +template<class T> +const SPIRVDecoder& +decode(const SPIRVDecoder& I, T &V) { +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if (SPIRVUseTextFormat) { + std::string W; + I.IS >> W; + V = getNameMap(V).rmap(W); + SPIRVDBG(spvdbgs() << "Read word: W = " << W << " V = " << V << '\n'); + return I; + } +#endif + return DecodeBinary(I, V); +} + +template<class T> +const SPIRVEncoder& +encode(const SPIRVEncoder& O, T V) { +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if (SPIRVUseTextFormat) { + O.OS << getNameMap(V).map(V) << " "; + return O; + } +#endif + return O << static_cast<SPIRVWord>(V); +} + +#define SPIRV_DEF_ENCDEC(Type) \ +const SPIRVDecoder& \ +operator>>(const SPIRVDecoder& I, Type &V) { \ + return decode(I, V); \ +}\ +const SPIRVEncoder& \ +operator<<(const SPIRVEncoder& O, Type V) { \ + return encode(O, V); \ +} + +SPIRV_DEF_ENCDEC(Op) +SPIRV_DEF_ENCDEC(Capability) +SPIRV_DEF_ENCDEC(Decoration) +SPIRV_DEF_ENCDEC(OCLExtOpKind) +SPIRV_DEF_ENCDEC(LinkageType) + +// Read a string with padded 0's at the end so that they form a stream of +// words. +const SPIRVDecoder& +operator>>(const SPIRVDecoder&I, std::string& Str) { +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if (SPIRVUseTextFormat) { + readQuotedString(I.IS, Str); + SPIRVDBG(spvdbgs() << "Read string: \"" << Str << "\"\n"); + return I; + } +#endif + + uint64_t Count = 0; + char Ch; + while (I.IS.get(Ch) && Ch != '\0') { + Str += Ch; + ++Count; + } + Count = (Count + 1) % 4; + Count = Count ? 4 - Count : 0; + for (;Count; --Count) { + I.IS >> Ch; + assert(Ch == '\0' && "Invalid string in SPIRV"); + } + SPIRVDBG(spvdbgs() << "Read string: \"" << Str << "\"\n"); + return I; +} + +// Write a string with padded 0's at the end so that they form a stream of +// words. +const SPIRVEncoder& +operator<<(const SPIRVEncoder&O, const std::string& Str) { +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if (SPIRVUseTextFormat) { + writeQuotedString(O.OS, Str); + return O; + } +#endif + + size_t L = Str.length(); + O.OS.write(Str.c_str(), L); + char Zeros[4] = {0, 0, 0, 0}; + O.OS.write(Zeros, 4-L%4); + return O; +} + +bool +SPIRVDecoder::getWordCountAndOpCode() { + if (IS.eof()) { + WordCount = 0; + OpCode = OpNop; + SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode EOF " << + WordCount << " " << OpCode << '\n'); + return false; + } +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if (SPIRVUseTextFormat) { + *this >> WordCount; + assert(!IS.bad() && "SPIRV stream is bad"); + if (IS.fail()) { + WordCount = 0; + OpCode = OpNop; + SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode FAIL " << + WordCount << " " << OpCode << '\n'); + return false; + } + *this >> OpCode; + } else { +#endif + SPIRVWord WordCountAndOpCode; + *this >> WordCountAndOpCode; + WordCount = WordCountAndOpCode >> 16; + OpCode = static_cast<Op>(WordCountAndOpCode & 0xFFFF); +#ifdef _SPIRV_SUPPORT_TEXT_FMT + } +#endif + assert(!IS.bad() && "SPIRV stream is bad"); + if (IS.fail()) { + WordCount = 0; + OpCode = OpNop; + SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode FAIL " << + WordCount << " " << OpCode << '\n'); + return false; + } + SPIRVDBG(spvdbgs() << "[SPIRVDecoder] getWordCountAndOpCode " << WordCount << + " " << OpCodeNameMap::map(OpCode) << '\n'); + return true; +} + +SPIRVEntry * +SPIRVDecoder::getEntry() { + if (WordCount == 0 || OpCode == OpNop) + return nullptr; + SPIRVEntry *Entry = SPIRVEntry::create(OpCode); + assert(Entry); + Entry->setModule(&M); + if (isModuleScopeAllowedOpCode(OpCode) && !Scope) {} + else + Entry->setScope(Scope); + Entry->setWordCount(WordCount); + if (OpCode != OpLine) + Entry->setLine(M.getCurrentLine()); + IS >> *Entry; + if (Entry->isEndOfBlock() || OpCode == OpNoLine) + M.setCurrentLine(nullptr); + assert(!IS.bad() && !IS.fail() && "SPIRV stream fails"); + return Entry; +} + +void +SPIRVDecoder::validate()const { + assert(OpCode != OpNop && "Invalid op code"); + assert(WordCount && "Invalid word count"); + assert(!IS.bad() && "Bad iInput stream"); +} + +spv_ostream & +operator<<(spv_ostream &O, const SPIRVNL &E) { +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if (SPIRVUseTextFormat) + O << '\n'; +#endif + return O; +} + +} // end of SPIRV namespace + diff --git a/lib/SPIRV/libSPIRV/SPIRVStream.h b/lib/SPIRV/libSPIRV/SPIRVStream.h index 7cd0b1c..bc22799 100644 --- a/lib/SPIRV/libSPIRV/SPIRVStream.h +++ b/lib/SPIRV/libSPIRV/SPIRVStream.h @@ -1,202 +1,202 @@ -//===- SPIRVStream.h – Class to represent a SPIR-V Stream --------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines Word class for SPIR-V.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVSTREAM_H
-#define SPIRVSTREAM_H
-
-#include "SPIRVDebug.h"
-#include "SPIRVModule.h"
-#include "SPIRVExtInst.h"
-#include <algorithm>
-#include <cstdint>
-#include <iostream>
-#include <iterator>
-#include <vector>
-#include <string>
-
-namespace SPIRV{
-
-#ifndef _SPIRV_SUPPORT_TEXT_FMT
-#define _SPIRV_SUPPORT_TEXT_FMT
-#endif
-
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
-// Use textual format for SPIRV.
-extern bool SPIRVUseTextFormat;
-#endif
-
-class SPIRVFunction;
-class SPIRVBasicBlock;
-
-class SPIRVDecoder {
-public:
- SPIRVDecoder(std::istream& InputStream, SPIRVModule& Module)
- :IS(InputStream), M(Module), WordCount(0), OpCode(OpNop),
- Scope(NULL){}
- SPIRVDecoder(std::istream& InputStream, SPIRVFunction& F);
- SPIRVDecoder(std::istream& InputStream, SPIRVBasicBlock &BB);
-
- void setScope(SPIRVEntry *);
- bool getWordCountAndOpCode();
- SPIRVEntry *getEntry();
- void validate()const;
-
- std::istream &IS;
- SPIRVModule &M;
- SPIRVWord WordCount;
- Op OpCode;
- SPIRVEntry *Scope; // A function or basic block
-};
-
-class SPIRVEncoder {
-public:
- explicit SPIRVEncoder(spv_ostream &OutputStream) : OS(OutputStream) {}
- spv_ostream &OS;
-};
-
-/// Output a new line in text mode. Do nothing in binary mode.
-class SPIRVNL {
- friend spv_ostream &operator<<(spv_ostream &O, const SPIRVNL &E);
-};
-
-template<typename T>
-const SPIRVDecoder&
-DecodeBinary(const SPIRVDecoder& I, T &V) {
- uint32_t W;
- I.IS.read(reinterpret_cast<char*>(&W), sizeof(W));
- V = static_cast<T>(W);
- SPIRVDBG(spvdbgs() << "Read word: W = " << W << " V = " << V << '\n');
- return I;
-}
-
-template<typename T>
-const SPIRVDecoder&
-operator>>(const SPIRVDecoder& I, T &V) {
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
- if (SPIRVUseTextFormat) {
- uint32_t W;
- I.IS >> W;
- V = static_cast<T>(W);
- SPIRVDBG(spvdbgs() << "Read word: W = " << W << " V = " << V << '\n');
- return I;
- }
-#endif
- return DecodeBinary(I, V);
-}
-
-template<typename T>
-const SPIRVDecoder&
-operator>>(const SPIRVDecoder& I, T *&P) {
- SPIRVId Id;
- I >> Id;
- P = static_cast<T*>(I.M.getEntry(Id));
- return I;
-}
-
-template<typename IterTy>
-const SPIRVDecoder&
-operator>>(const SPIRVDecoder& Decoder, const std::pair<IterTy,IterTy> &Range) {
- for (IterTy I = Range.first, E = Range.second; I != E; ++I)
- Decoder >> *I;
- return Decoder;
-}
-
-template<typename T>
-const SPIRVDecoder&
-operator>>(const SPIRVDecoder& I, std::vector<T> &V) {
- for (size_t i = 0, e = V.size(); i != e; ++i)
- I >> V[i];
- return I;
-}
-
-template<typename T>
-const SPIRVEncoder&
-operator<<(const SPIRVEncoder& O, T V) {
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
- if (SPIRVUseTextFormat) {
- O.OS << V << " ";
- return O;
- }
-#endif
- uint32_t W = static_cast<uint32_t>(V);
- O.OS.write(reinterpret_cast<char*>(&W), sizeof(W));
- return O;
-}
-
-template<typename T>
-const SPIRVEncoder&
-operator<<(const SPIRVEncoder& O, T* P) {
- return O << P->getId();
-}
-
-template<typename T>
-const SPIRVEncoder&
-operator<<(const SPIRVEncoder& O, const std::vector<T>& V) {
- for (size_t i = 0, e = V.size(); i != e; ++i)
- O << V[i];
- return O;
-}
-
-template<typename IterTy>
-const SPIRVEncoder&
-operator<<(const SPIRVEncoder& Encoder, const std::pair<IterTy,IterTy> &Range) {
- for (IterTy I = Range.first, E = Range.second; I != E; ++I)
- Encoder << *I;
- return Encoder;
-}
-
-#define SPIRV_DEC_ENCDEC(Type) \
-const SPIRVEncoder& \
-operator<<(const SPIRVEncoder& O, Type V); \
-const SPIRVDecoder& \
-operator>>(const SPIRVDecoder& I, Type &V);
-
-SPIRV_DEC_ENCDEC(Op)
-SPIRV_DEC_ENCDEC(Capability)
-SPIRV_DEC_ENCDEC(Decoration)
-SPIRV_DEC_ENCDEC(OCLExtOpKind)
-SPIRV_DEC_ENCDEC(LinkageType)
-
-const SPIRVEncoder&
-operator<<(const SPIRVEncoder&O, const std::string& Str);
-const SPIRVDecoder&
-operator>>(const SPIRVDecoder&I, std::string& Str);
-
-} // namespace SPIRV
-#endif
+//===- SPIRVStream.h – Class to represent a SPIR-V Stream --------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines Word class for SPIR-V. +/// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVSTREAM_H +#define SPIRVSTREAM_H + +#include "SPIRVDebug.h" +#include "SPIRVModule.h" +#include "SPIRVExtInst.h" +#include <algorithm> +#include <cstdint> +#include <iostream> +#include <iterator> +#include <vector> +#include <string> + +namespace SPIRV{ + +#ifndef _SPIRV_SUPPORT_TEXT_FMT +#define _SPIRV_SUPPORT_TEXT_FMT +#endif + +#ifdef _SPIRV_SUPPORT_TEXT_FMT +// Use textual format for SPIRV. +extern bool SPIRVUseTextFormat; +#endif + +class SPIRVFunction; +class SPIRVBasicBlock; + +class SPIRVDecoder { +public: + SPIRVDecoder(std::istream& InputStream, SPIRVModule& Module) + :IS(InputStream), M(Module), WordCount(0), OpCode(OpNop), + Scope(NULL){} + SPIRVDecoder(std::istream& InputStream, SPIRVFunction& F); + SPIRVDecoder(std::istream& InputStream, SPIRVBasicBlock &BB); + + void setScope(SPIRVEntry *); + bool getWordCountAndOpCode(); + SPIRVEntry *getEntry(); + void validate()const; + + std::istream &IS; + SPIRVModule &M; + SPIRVWord WordCount; + Op OpCode; + SPIRVEntry *Scope; // A function or basic block +}; + +class SPIRVEncoder { +public: + explicit SPIRVEncoder(spv_ostream &OutputStream) : OS(OutputStream) {} + spv_ostream &OS; +}; + +/// Output a new line in text mode. Do nothing in binary mode. +class SPIRVNL { + friend spv_ostream &operator<<(spv_ostream &O, const SPIRVNL &E); +}; + +template<typename T> +const SPIRVDecoder& +DecodeBinary(const SPIRVDecoder& I, T &V) { + uint32_t W; + I.IS.read(reinterpret_cast<char*>(&W), sizeof(W)); + V = static_cast<T>(W); + SPIRVDBG(spvdbgs() << "Read word: W = " << W << " V = " << V << '\n'); + return I; +} + +template<typename T> +const SPIRVDecoder& +operator>>(const SPIRVDecoder& I, T &V) { +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if (SPIRVUseTextFormat) { + uint32_t W; + I.IS >> W; + V = static_cast<T>(W); + SPIRVDBG(spvdbgs() << "Read word: W = " << W << " V = " << V << '\n'); + return I; + } +#endif + return DecodeBinary(I, V); +} + +template<typename T> +const SPIRVDecoder& +operator>>(const SPIRVDecoder& I, T *&P) { + SPIRVId Id; + I >> Id; + P = static_cast<T*>(I.M.getEntry(Id)); + return I; +} + +template<typename IterTy> +const SPIRVDecoder& +operator>>(const SPIRVDecoder& Decoder, const std::pair<IterTy,IterTy> &Range) { + for (IterTy I = Range.first, E = Range.second; I != E; ++I) + Decoder >> *I; + return Decoder; +} + +template<typename T> +const SPIRVDecoder& +operator>>(const SPIRVDecoder& I, std::vector<T> &V) { + for (size_t i = 0, e = V.size(); i != e; ++i) + I >> V[i]; + return I; +} + +template<typename T> +const SPIRVEncoder& +operator<<(const SPIRVEncoder& O, T V) { +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if (SPIRVUseTextFormat) { + O.OS << V << " "; + return O; + } +#endif + uint32_t W = static_cast<uint32_t>(V); + O.OS.write(reinterpret_cast<char*>(&W), sizeof(W)); + return O; +} + +template<typename T> +const SPIRVEncoder& +operator<<(const SPIRVEncoder& O, T* P) { + return O << P->getId(); +} + +template<typename T> +const SPIRVEncoder& +operator<<(const SPIRVEncoder& O, const std::vector<T>& V) { + for (size_t i = 0, e = V.size(); i != e; ++i) + O << V[i]; + return O; +} + +template<typename IterTy> +const SPIRVEncoder& +operator<<(const SPIRVEncoder& Encoder, const std::pair<IterTy,IterTy> &Range) { + for (IterTy I = Range.first, E = Range.second; I != E; ++I) + Encoder << *I; + return Encoder; +} + +#define SPIRV_DEC_ENCDEC(Type) \ +const SPIRVEncoder& \ +operator<<(const SPIRVEncoder& O, Type V); \ +const SPIRVDecoder& \ +operator>>(const SPIRVDecoder& I, Type &V); + +SPIRV_DEC_ENCDEC(Op) +SPIRV_DEC_ENCDEC(Capability) +SPIRV_DEC_ENCDEC(Decoration) +SPIRV_DEC_ENCDEC(OCLExtOpKind) +SPIRV_DEC_ENCDEC(LinkageType) + +const SPIRVEncoder& +operator<<(const SPIRVEncoder&O, const std::string& Str); +const SPIRVDecoder& +operator>>(const SPIRVDecoder&I, std::string& Str); + +} // namespace SPIRV +#endif diff --git a/lib/SPIRV/libSPIRV/SPIRVType.cpp b/lib/SPIRV/libSPIRV/SPIRVType.cpp index 82cf0e0..926fbce 100644 --- a/lib/SPIRV/libSPIRV/SPIRVType.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVType.cpp @@ -1,293 +1,293 @@ -//===- SPIRVtype.cpp – Class to represent a SPIR-V type ----------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file implements the types defined in SPIRV spec with op codes.
-///
-//===----------------------------------------------------------------------===//
-
-#include "SPIRVType.h"
-#include "SPIRVModule.h"
-#include "SPIRVDecorate.h"
-#include "SPIRVValue.h"
-
-#include <cassert>
-
-namespace SPIRV{
-
-SPIRVType*
-SPIRVType::getArrayElementType() const {
- assert(OpCode == OpTypeArray && "Not array type");
- return static_cast<const SPIRVTypeArray *const>(this)->getElementType();
-}
-
-uint64_t
-SPIRVType::getArrayLength() const {
- assert(OpCode == OpTypeArray && "Not array type");
- return static_cast<const SPIRVTypeArray *const>(this)->getLength()->
- getZExtIntValue();
-}
-
-SPIRVWord
-SPIRVType::getBitWidth() const {
- if (isTypeVector())
- return getVectorComponentType()->getBitWidth();
- if (isTypeBool())
- return 1;
- return isTypeInt()? getIntegerBitWidth() : getFloatBitWidth();
-}
-
-SPIRVWord
-SPIRVType::getFloatBitWidth()const {
- assert(OpCode == OpTypeFloat && "Not a float type");
- return static_cast<const SPIRVTypeFloat *const>(this)->getBitWidth();
-}
-
-SPIRVWord
-SPIRVType::getIntegerBitWidth()const {
- assert((OpCode == OpTypeInt || OpCode == OpTypeBool) &&
- "Not an integer type");
- if (isTypeBool())
- return 1;
- return static_cast<const SPIRVTypeInt *const>(this)->getBitWidth();
-}
-
-SPIRVType *
-SPIRVType::getFunctionReturnType() const {
- assert(OpCode == OpTypeFunction);
- return static_cast<const SPIRVTypeFunction *const>(this)->getReturnType();
-}
-
-SPIRVType *
-SPIRVType::getPointerElementType()const {
- assert(OpCode == OpTypePointer && "Not a pointer type");
- return static_cast<const SPIRVTypePointer *const>(this)->getElementType();
-}
-
-SPIRVStorageClassKind
-SPIRVType::getPointerStorageClass() const {
- assert(OpCode == OpTypePointer && "Not a pointer type");
- return static_cast<const SPIRVTypePointer *const>(this)->getStorageClass();
-}
-
-SPIRVType*
-SPIRVType::getStructMemberType(size_t Index) const {
- assert(OpCode == OpTypeStruct && "Not struct type");
- return static_cast<const SPIRVTypeStruct *const>(this)->getMemberType(Index);
-}
-
-SPIRVWord
-SPIRVType::getStructMemberCount() const {
- assert(OpCode == OpTypeStruct && "Not struct type");
- return static_cast<const SPIRVTypeStruct *const>(this)->getMemberCount();
-}
-
-SPIRVWord
-SPIRVType::getVectorComponentCount() const {
- assert(OpCode == OpTypeVector && "Not vector type");
- return static_cast<const SPIRVTypeVector *const>(this)->getComponentCount();
-}
-
-SPIRVType*
-SPIRVType::getVectorComponentType() const {
- assert(OpCode == OpTypeVector && "Not vector type");
- return static_cast<const SPIRVTypeVector *const>(this)->getComponentType();
-}
-
-bool
-SPIRVType::isTypeVoid() const {
- return OpCode == OpTypeVoid;
-}
-bool
-SPIRVType::isTypeArray() const {
- return OpCode == OpTypeArray;
-}
-
-bool
-SPIRVType::isTypeBool()const {
- return OpCode == OpTypeBool;
-}
-
-bool
-SPIRVType::isTypeComposite() const {
- return isTypeVector() || isTypeArray() || isTypeStruct();
-}
-
-bool
-SPIRVType::isTypeFloat(unsigned Bits)const {
- return isType<SPIRVTypeFloat>(this, Bits);
-}
-
-bool
-SPIRVType::isTypeOCLImage()const {
- return isTypeImage() && static_cast<const SPIRVTypeImage *>(this)->
- isOCLImage();
-}
-
-bool
-SPIRVType::isTypePipe()const {
- return OpCode == OpTypePipe;
-}
-
-bool
-SPIRVType::isTypePipeStorage() const {
- return OpCode == OpTypePipeStorage;
-}
-
-bool
-SPIRVType::isTypeReserveId() const {
- return OpCode == OpTypeReserveId;
-}
-
-bool
-SPIRVType::isTypeInt(unsigned Bits)const {
- return isType<SPIRVTypeInt>(this, Bits);
-}
-
-bool
-SPIRVType::isTypePointer()const {
- return OpCode == OpTypePointer;
-}
-
-bool
-SPIRVType::isTypeOpaque()const {
- return OpCode == OpTypeOpaque;
-}
-
-bool
-SPIRVType::isTypeEvent()const {
- return OpCode == OpTypeEvent;
-}
-
-bool
-SPIRVType::isTypeDeviceEvent()const {
- return OpCode == OpTypeDeviceEvent;
-}
-
-bool
-SPIRVType::isTypeSampler()const {
- return OpCode == OpTypeSampler;
-}
-
-bool
-SPIRVType::isTypeImage()const {
- return OpCode == OpTypeImage;
-}
-
-bool
-SPIRVType::isTypeStruct() const {
- return OpCode == OpTypeStruct;
-}
-
-bool
-SPIRVType::isTypeVector() const {
- return OpCode == OpTypeVector;
-}
-
-bool
-SPIRVType::isTypeVectorBool() const {
- return isTypeVector() && getVectorComponentType()->isTypeBool();
-}
-
-bool
-SPIRVType::isTypeVectorInt() const {
- return isTypeVector() && getVectorComponentType()->isTypeInt();
-}
-
-bool
-SPIRVType::isTypeVectorFloat() const {
- return isTypeVector() && getVectorComponentType()->isTypeFloat();
-}
-
-bool
-SPIRVType::isTypeVectorOrScalarBool() const {
- return isTypeBool() || isTypeVectorBool();
-}
-
-bool
-SPIRVType::isTypeVectorOrScalarInt() const {
- return isTypeInt() || isTypeVectorInt();
-}
-
-bool
-SPIRVType::isTypeVectorOrScalarFloat() const {
- return isTypeFloat() || isTypeVectorFloat();
-}
-
-bool
-SPIRVTypeStruct::isPacked() const {
- return hasDecorate(DecorationCPacked);
-}
-
-void
-SPIRVTypeStruct::setPacked(bool Packed) {
- if (Packed)
- addDecorate(new SPIRVDecorate(DecorationCPacked, this));
- else
- eraseDecorate(DecorationCPacked);
-}
-
-SPIRVTypeArray::SPIRVTypeArray(SPIRVModule *M, SPIRVId TheId, SPIRVType *TheElemType,
- SPIRVConstant* TheLength)
- :SPIRVType(M, 4, OpTypeArray, TheId), ElemType(TheElemType),
- Length(TheLength->getId()){
- validate();
- }
-
-void
-SPIRVTypeArray::validate()const {
- SPIRVEntry::validate();
- ElemType->validate();
- assert(getValue(Length)->getType()->isTypeInt() &&
- get<SPIRVConstant>(Length)->getZExtIntValue() > 0);
-}
-
-SPIRVConstant*
-SPIRVTypeArray::getLength() const {
- return get<SPIRVConstant>(Length);
-}
-
-_SPIRV_IMP_ENCDEC3(SPIRVTypeArray, Id, ElemType, Length)
-
-void SPIRVTypeForwardPointer::encode(spv_ostream &O) const {
- getEncoder(O) << Pointer << SC;
-}
-
-void SPIRVTypeForwardPointer::decode(std::istream &I) {
- auto Decoder = getDecoder(I);
- SPIRVId PointerId;
- Decoder >> PointerId >> SC;
-}
-}
-
+//===- SPIRVtype.cpp – Class to represent a SPIR-V type ----------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file implements the types defined in SPIRV spec with op codes. +/// +//===----------------------------------------------------------------------===// + +#include "SPIRVType.h" +#include "SPIRVModule.h" +#include "SPIRVDecorate.h" +#include "SPIRVValue.h" + +#include <cassert> + +namespace SPIRV{ + +SPIRVType* +SPIRVType::getArrayElementType() const { + assert(OpCode == OpTypeArray && "Not array type"); + return static_cast<const SPIRVTypeArray *const>(this)->getElementType(); +} + +uint64_t +SPIRVType::getArrayLength() const { + assert(OpCode == OpTypeArray && "Not array type"); + return static_cast<const SPIRVTypeArray *const>(this)->getLength()-> + getZExtIntValue(); +} + +SPIRVWord +SPIRVType::getBitWidth() const { + if (isTypeVector()) + return getVectorComponentType()->getBitWidth(); + if (isTypeBool()) + return 1; + return isTypeInt()? getIntegerBitWidth() : getFloatBitWidth(); +} + +SPIRVWord +SPIRVType::getFloatBitWidth()const { + assert(OpCode == OpTypeFloat && "Not a float type"); + return static_cast<const SPIRVTypeFloat *const>(this)->getBitWidth(); +} + +SPIRVWord +SPIRVType::getIntegerBitWidth()const { + assert((OpCode == OpTypeInt || OpCode == OpTypeBool) && + "Not an integer type"); + if (isTypeBool()) + return 1; + return static_cast<const SPIRVTypeInt *const>(this)->getBitWidth(); +} + +SPIRVType * +SPIRVType::getFunctionReturnType() const { + assert(OpCode == OpTypeFunction); + return static_cast<const SPIRVTypeFunction *const>(this)->getReturnType(); +} + +SPIRVType * +SPIRVType::getPointerElementType()const { + assert(OpCode == OpTypePointer && "Not a pointer type"); + return static_cast<const SPIRVTypePointer *const>(this)->getElementType(); +} + +SPIRVStorageClassKind +SPIRVType::getPointerStorageClass() const { + assert(OpCode == OpTypePointer && "Not a pointer type"); + return static_cast<const SPIRVTypePointer *const>(this)->getStorageClass(); +} + +SPIRVType* +SPIRVType::getStructMemberType(size_t Index) const { + assert(OpCode == OpTypeStruct && "Not struct type"); + return static_cast<const SPIRVTypeStruct *const>(this)->getMemberType(Index); +} + +SPIRVWord +SPIRVType::getStructMemberCount() const { + assert(OpCode == OpTypeStruct && "Not struct type"); + return static_cast<const SPIRVTypeStruct *const>(this)->getMemberCount(); +} + +SPIRVWord +SPIRVType::getVectorComponentCount() const { + assert(OpCode == OpTypeVector && "Not vector type"); + return static_cast<const SPIRVTypeVector *const>(this)->getComponentCount(); +} + +SPIRVType* +SPIRVType::getVectorComponentType() const { + assert(OpCode == OpTypeVector && "Not vector type"); + return static_cast<const SPIRVTypeVector *const>(this)->getComponentType(); +} + +bool +SPIRVType::isTypeVoid() const { + return OpCode == OpTypeVoid; +} +bool +SPIRVType::isTypeArray() const { + return OpCode == OpTypeArray; +} + +bool +SPIRVType::isTypeBool()const { + return OpCode == OpTypeBool; +} + +bool +SPIRVType::isTypeComposite() const { + return isTypeVector() || isTypeArray() || isTypeStruct(); +} + +bool +SPIRVType::isTypeFloat(unsigned Bits)const { + return isType<SPIRVTypeFloat>(this, Bits); +} + +bool +SPIRVType::isTypeOCLImage()const { + return isTypeImage() && static_cast<const SPIRVTypeImage *>(this)-> + isOCLImage(); +} + +bool +SPIRVType::isTypePipe()const { + return OpCode == OpTypePipe; +} + +bool +SPIRVType::isTypePipeStorage() const { + return OpCode == OpTypePipeStorage; +} + +bool +SPIRVType::isTypeReserveId() const { + return OpCode == OpTypeReserveId; +} + +bool +SPIRVType::isTypeInt(unsigned Bits)const { + return isType<SPIRVTypeInt>(this, Bits); +} + +bool +SPIRVType::isTypePointer()const { + return OpCode == OpTypePointer; +} + +bool +SPIRVType::isTypeOpaque()const { + return OpCode == OpTypeOpaque; +} + +bool +SPIRVType::isTypeEvent()const { + return OpCode == OpTypeEvent; +} + +bool +SPIRVType::isTypeDeviceEvent()const { + return OpCode == OpTypeDeviceEvent; +} + +bool +SPIRVType::isTypeSampler()const { + return OpCode == OpTypeSampler; +} + +bool +SPIRVType::isTypeImage()const { + return OpCode == OpTypeImage; +} + +bool +SPIRVType::isTypeStruct() const { + return OpCode == OpTypeStruct; +} + +bool +SPIRVType::isTypeVector() const { + return OpCode == OpTypeVector; +} + +bool +SPIRVType::isTypeVectorBool() const { + return isTypeVector() && getVectorComponentType()->isTypeBool(); +} + +bool +SPIRVType::isTypeVectorInt() const { + return isTypeVector() && getVectorComponentType()->isTypeInt(); +} + +bool +SPIRVType::isTypeVectorFloat() const { + return isTypeVector() && getVectorComponentType()->isTypeFloat(); +} + +bool +SPIRVType::isTypeVectorOrScalarBool() const { + return isTypeBool() || isTypeVectorBool(); +} + +bool +SPIRVType::isTypeVectorOrScalarInt() const { + return isTypeInt() || isTypeVectorInt(); +} + +bool +SPIRVType::isTypeVectorOrScalarFloat() const { + return isTypeFloat() || isTypeVectorFloat(); +} + +bool +SPIRVTypeStruct::isPacked() const { + return hasDecorate(DecorationCPacked); +} + +void +SPIRVTypeStruct::setPacked(bool Packed) { + if (Packed) + addDecorate(new SPIRVDecorate(DecorationCPacked, this)); + else + eraseDecorate(DecorationCPacked); +} + +SPIRVTypeArray::SPIRVTypeArray(SPIRVModule *M, SPIRVId TheId, SPIRVType *TheElemType, + SPIRVConstant* TheLength) + :SPIRVType(M, 4, OpTypeArray, TheId), ElemType(TheElemType), + Length(TheLength->getId()){ + validate(); + } + +void +SPIRVTypeArray::validate()const { + SPIRVEntry::validate(); + ElemType->validate(); + assert(getValue(Length)->getType()->isTypeInt() && + get<SPIRVConstant>(Length)->getZExtIntValue() > 0); +} + +SPIRVConstant* +SPIRVTypeArray::getLength() const { + return get<SPIRVConstant>(Length); +} + +_SPIRV_IMP_ENCDEC3(SPIRVTypeArray, Id, ElemType, Length) + +void SPIRVTypeForwardPointer::encode(spv_ostream &O) const { + getEncoder(O) << Pointer << SC; +} + +void SPIRVTypeForwardPointer::decode(std::istream &I) { + auto Decoder = getDecoder(I); + SPIRVId PointerId; + Decoder >> PointerId >> SC; +} +} + diff --git a/lib/SPIRV/libSPIRV/SPIRVType.h b/lib/SPIRV/libSPIRV/SPIRVType.h index 6452789..7f1f429 100644 --- a/lib/SPIRV/libSPIRV/SPIRVType.h +++ b/lib/SPIRV/libSPIRV/SPIRVType.h @@ -1,764 +1,764 @@ -//===- SPIRVType.h - Class to represent a SPIR-V Type -----------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines the types defined in SPIRV spec with op codes.
-///
-/// The name of the SPIR-V types follow the op code name in the spec, e.g.
-/// SPIR-V type with op code name OpTypeInt is named as SPIRVTypeInt. This is
-/// for readability and ease of using macro to handle types.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVTYPE_HPP_
-#define SPIRVTYPE_HPP_
-
-#include "SPIRVEntry.h"
-#include "SPIRVStream.h"
-
-#include <cassert>
-#include <tuple>
-#include <vector>
-#include <map>
-#include <iostream>
-
-namespace SPIRV{
-
-class SPIRVType: public SPIRVEntry {
-public:
- // Complete constructor
- SPIRVType(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
- SPIRVId TheId)
- :SPIRVEntry(M, TheWordCount, TheOpCode, TheId){}
- // Incomplete constructor
- SPIRVType(Op TheOpCode):SPIRVEntry(TheOpCode){}
-
- SPIRVType *getArrayElementType() const;
- uint64_t getArrayLength() const;
- unsigned getBitWidth() const;
- unsigned getFloatBitWidth() const;
- SPIRVType *getFunctionReturnType() const;
- unsigned getIntegerBitWidth() const;
- SPIRVType *getPointerElementType() const;
- SPIRVStorageClassKind getPointerStorageClass() const;
- SPIRVType *getStructMemberType(size_t) const;
- SPIRVWord getStructMemberCount() const;
- SPIRVWord getVectorComponentCount() const;
- SPIRVType *getVectorComponentType() const;
-
- bool isTypeVoid() const;
- bool isTypeArray() const;
- bool isTypeBool() const;
- bool isTypeComposite() const;
- bool isTypeEvent() const;
- bool isTypeDeviceEvent() const;
- bool isTypeReserveId() const;
- bool isTypeFloat(unsigned Bits = 0) const;
- bool isTypeImage() const;
- bool isTypeOCLImage() const;
- bool isTypePipe()const;
- bool isTypePipeStorage() const;
- bool isTypeInt(unsigned Bits = 0) const;
- bool isTypeOpaque() const;
- bool isTypePointer() const;
- bool isTypeSampler() const;
- bool isTypeStruct() const;
- bool isTypeVector() const;
- bool isTypeVectorInt() const;
- bool isTypeVectorFloat() const;
- bool isTypeVectorBool() const;
- bool isTypeVectorOrScalarInt() const;
- bool isTypeVectorOrScalarFloat() const;
- bool isTypeVectorOrScalarBool() const;
-};
-
-class SPIRVTypeVoid:public SPIRVType {
-public:
- // Complete constructor
- SPIRVTypeVoid(SPIRVModule *M, SPIRVId TheId)
- :SPIRVType(M, 2, OpTypeVoid, TheId){}
- // Incomplete constructor
- SPIRVTypeVoid():SPIRVType(OpTypeVoid){}
-protected:
- _SPIRV_DEF_ENCDEC1(Id)
-};
-
-class SPIRVTypeBool:public SPIRVType {
-public:
- // Complete constructor
- SPIRVTypeBool(SPIRVModule *M, SPIRVId TheId)
- :SPIRVType(M, 2, OpTypeBool, TheId){}
- // Incomplete constructor
- SPIRVTypeBool():SPIRVType(OpTypeBool){}
-protected:
- _SPIRV_DEF_ENCDEC1(Id)
-};
-
-class SPIRVTypeInt:public SPIRVType {
-public:
- static const Op OC = OpTypeInt;
- // Complete constructor
- SPIRVTypeInt(SPIRVModule *M, SPIRVId TheId, unsigned TheBitWidth,
- bool ItIsSigned)
- :SPIRVType(M, 4, OC , TheId), BitWidth(TheBitWidth),
- IsSigned(ItIsSigned){
- validate();
- }
- // Incomplete constructor
- SPIRVTypeInt():SPIRVType(OC), BitWidth(0), IsSigned(false){}
-
- unsigned getBitWidth() const { return BitWidth;}
- bool isSigned() const { return IsSigned;}
- SPIRVCapVec getRequiredCapability() const {
- SPIRVCapVec CV;
- switch (BitWidth) {
- case 8:
- CV.push_back(CapabilityInt8);
- break;
- case 16:
- CV.push_back(CapabilityInt16);
- break;
- case 64:
- CV.push_back(CapabilityInt64);
- break;
- default:
- break;
- }
- return std::move(CV);
- }
-
-protected:
- _SPIRV_DEF_ENCDEC3(Id, BitWidth, IsSigned)
- void validate()const {
- SPIRVEntry::validate();
- assert(BitWidth > 1 && BitWidth <= 64 && "Invalid bit width");
- }
-private:
- unsigned BitWidth; // Bit width
- bool IsSigned; // Whether it is signed
-};
-
-class SPIRVTypeFloat:public SPIRVType {
-public:
- static const Op OC = OpTypeFloat;
- // Complete constructor
- SPIRVTypeFloat(SPIRVModule *M, SPIRVId TheId, unsigned TheBitWidth)
- :SPIRVType(M, 3, OC, TheId), BitWidth(TheBitWidth){}
- // Incomplete constructor
- SPIRVTypeFloat():SPIRVType(OC), BitWidth(0){}
-
- unsigned getBitWidth() const { return BitWidth;}
-
- SPIRVCapVec getRequiredCapability() const {
- SPIRVCapVec CV;
- if (isTypeFloat(16)) {
- CV.push_back(CapabilityFloat16Buffer);
- auto extensions = getModule()->getExtension();
- if (std::any_of(extensions.begin(), extensions.end(),
- [](const std::string &I){return I == "cl_khr_fp16";}))
- CV.push_back(CapabilityFloat16);
- }
- else if (isTypeFloat(64))
- CV.push_back(CapabilityFloat64);
- return std::move(CV);
- }
-
-
-protected:
- _SPIRV_DEF_ENCDEC2(Id, BitWidth)
- void validate()const {
- SPIRVEntry::validate();
- assert(BitWidth >= 16 && BitWidth <= 64 && "Invalid bit width");
- }
-private:
- unsigned BitWidth; // Bit width
-};
-
-class SPIRVTypePointer:public SPIRVType {
-public:
- // Complete constructor
- SPIRVTypePointer(SPIRVModule *M, SPIRVId TheId,
- SPIRVStorageClassKind TheStorageClass,
- SPIRVType *ElementType)
- :SPIRVType(M, 4, OpTypePointer, TheId), ElemStorageClass(TheStorageClass),
- ElemTypeId(ElementType->getId()){
- validate();
- }
- // Incomplete constructor
- SPIRVTypePointer():SPIRVType(OpTypePointer),
- ElemStorageClass(StorageClassFunction),
- ElemTypeId(0){}
-
- SPIRVType *getElementType() const {
- return static_cast<SPIRVType *>(getEntry(ElemTypeId));
- }
- SPIRVStorageClassKind getStorageClass() const { return ElemStorageClass;}
- SPIRVCapVec getRequiredCapability() const {
- auto Cap = getVec(CapabilityAddresses);
- if (getElementType()->isTypeFloat(16))
- Cap.push_back(CapabilityFloat16Buffer);
- auto C = getCapability(ElemStorageClass);
- Cap.insert(Cap.end(), C.begin(), C.end());
- return Cap;
- }
- virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const {
- return std::vector<SPIRVEntry*>(1, getEntry(ElemTypeId));
- }
-
-protected:
- _SPIRV_DEF_ENCDEC3(Id, ElemStorageClass, ElemTypeId)
- void validate()const {
- SPIRVEntry::validate();
- assert(isValid(ElemStorageClass));
- }
-private:
- SPIRVStorageClassKind ElemStorageClass; // Storage Class
- SPIRVId ElemTypeId;
-};
-
-class SPIRVTypeForwardPointer : public SPIRVEntryNoId<OpTypeForwardPointer> {
-public:
- SPIRVTypeForwardPointer(SPIRVModule *M, SPIRVTypePointer *Pointer,
- SPIRVStorageClassKind SC)
- : SPIRVEntryNoId(M, 3), Pointer(Pointer), SC(SC) {}
-
- SPIRVTypeForwardPointer()
- : Pointer(nullptr), SC(StorageClassUniformConstant) {}
-
- SPIRVTypePointer *getPointer() const { return Pointer; }
- _SPIRV_DCL_ENCDEC
-private:
- SPIRVTypePointer *Pointer;
- SPIRVStorageClassKind SC;
-};
-
-class SPIRVTypeVector:public SPIRVType {
-public:
- // Complete constructor
- SPIRVTypeVector(SPIRVModule *M, SPIRVId TheId, SPIRVType *TheCompType,
- SPIRVWord TheCompCount)
- :SPIRVType(M, 4, OpTypeVector, TheId), CompType(TheCompType),
- CompCount(TheCompCount){
- validate();
- }
- // Incomplete constructor
- SPIRVTypeVector():SPIRVType(OpTypeVector), CompType(nullptr),
- CompCount(0){}
-
- SPIRVType *getComponentType() const { return CompType;}
- SPIRVWord getComponentCount() const { return CompCount;}
- bool isValidIndex(SPIRVWord Index) const { return Index < CompCount;}
- SPIRVCapVec getRequiredCapability() const {
- SPIRVCapVec V(getComponentType()->getRequiredCapability());
- // Even though the capability name is "Vector16", it describes
- // usage of 8-component or 16-component vectors.
- if (CompCount >= 8)
- V.push_back(CapabilityVector16);
- return std::move(V);
- }
-
- virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const {
- return std::vector<SPIRVEntry*>(1, CompType);
- }
-
-protected:
- _SPIRV_DEF_ENCDEC3(Id, CompType, CompCount)
- void validate()const {
- SPIRVEntry::validate();
- CompType->validate();
- assert(CompCount == 2 || CompCount == 3 || CompCount == 4 ||
- CompCount == 8 || CompCount == 16);
- }
-private:
- SPIRVType *CompType; // Component Type
- SPIRVWord CompCount; // Component Count
-};
-
-class SPIRVConstant;
-class SPIRVTypeArray:public SPIRVType {
-public:
- // Complete constructor
- SPIRVTypeArray(SPIRVModule *M, SPIRVId TheId, SPIRVType *TheElemType,
- SPIRVConstant* TheLength);
- // Incomplete constructor
- SPIRVTypeArray():SPIRVType(OpTypeArray), ElemType(nullptr),
- Length(SPIRVID_INVALID){}
-
- SPIRVType *getElementType() const { return ElemType;}
- SPIRVConstant *getLength() const;
- SPIRVCapVec getRequiredCapability() const {
- return std::move(getElementType()->getRequiredCapability());
- }
- virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const {
- std::vector<SPIRVEntry*> Operands(2, ElemType);
- Operands[1] = (SPIRVEntry*)getLength();
- return Operands;
- }
-
-
-protected:
- _SPIRV_DCL_ENCDEC
- void validate()const;
-private:
- SPIRVType *ElemType; // Element Type
- SPIRVId Length; // Array Length
-};
-
-class SPIRVTypeOpaque:public SPIRVType {
-public:
- // Complete constructor
- SPIRVTypeOpaque(SPIRVModule *M, SPIRVId TheId, const std::string& TheName)
- :SPIRVType(M, 2 + getSizeInWords(TheName), OpTypeOpaque, TheId) {
- Name = TheName;
- validate();
- }
- // Incomplete constructor
- SPIRVTypeOpaque():SPIRVType(OpTypeOpaque){}
-
-protected:
- _SPIRV_DEF_ENCDEC2(Id, Name)
- void validate()const {
- SPIRVEntry::validate();
- }
-};
-
-struct SPIRVTypeImageDescriptor {
- SPIRVImageDimKind Dim;
- SPIRVWord Depth;
- SPIRVWord Arrayed;
- SPIRVWord MS;
- SPIRVWord Sampled;
- SPIRVWord Format;
- static std::tuple<std::tuple<SPIRVImageDimKind, SPIRVWord, SPIRVWord, SPIRVWord,
- SPIRVWord>, SPIRVWord>
- getAsTuple (const SPIRVTypeImageDescriptor &Desc) {
- return std::make_tuple(std::make_tuple(Desc.Dim, Desc.Depth, Desc.Arrayed,
- Desc.MS, Desc.Sampled), Desc.Format);
- }
- SPIRVTypeImageDescriptor():Dim(Dim1D), Depth(0), Arrayed(0),
- MS(0), Sampled(0), Format(0){}
- SPIRVTypeImageDescriptor(SPIRVImageDimKind Dim, SPIRVWord Cont, SPIRVWord Arr,
- SPIRVWord Comp, SPIRVWord Mult, SPIRVWord F):Dim(Dim), Depth(Cont),
- Arrayed(Arr), MS(Comp), Sampled(Mult), Format(F){}
-};
-
-template<> inline void
-SPIRVMap<std::string, SPIRVTypeImageDescriptor>::init() {
-#define _SPIRV_OP(x,...) {SPIRVTypeImageDescriptor S(__VA_ARGS__); \
- add(#x, S);}
-_SPIRV_OP(image1d_t, Dim1D, 0, 0, 0, 0, 0)
-_SPIRV_OP(image1d_buffer_t, DimBuffer, 0, 0, 0, 0, 0)
-_SPIRV_OP(image1d_array_t, Dim1D, 0, 1, 0, 0, 0)
-_SPIRV_OP(image2d_t, Dim2D, 0, 0, 0, 0, 0)
-_SPIRV_OP(image2d_array_t, Dim2D, 0, 1, 0, 0, 0)
-_SPIRV_OP(image2d_depth_t, Dim2D, 1, 0, 0, 0, 0)
-_SPIRV_OP(image2d_array_depth_t, Dim2D, 1, 1, 0, 0, 0)
-_SPIRV_OP(image2d_msaa_t, Dim2D, 0, 0, 1, 0, 0)
-_SPIRV_OP(image2d_array_msaa_t, Dim2D, 0, 1, 1, 0, 0)
-_SPIRV_OP(image2d_msaa_depth_t, Dim2D, 1, 0, 1, 0, 0)
-_SPIRV_OP(image2d_array_msaa_depth_t, Dim2D, 1, 1, 1, 0, 0)
-_SPIRV_OP(image3d_t, Dim3D, 0, 0, 0, 0, 0)
-#undef _SPIRV_OP
-}
-typedef SPIRVMap<std::string, SPIRVTypeImageDescriptor>
- OCLSPIRVImageTypeMap;
-
-// Comparision function required to use the struct as map key.
-inline bool
-operator<(const SPIRVTypeImageDescriptor &A,
- const SPIRVTypeImageDescriptor &B){
- return SPIRVTypeImageDescriptor::getAsTuple(A) <
- SPIRVTypeImageDescriptor::getAsTuple(B);
-}
-
-class SPIRVTypeImage:public SPIRVType {
-public:
- const static Op OC = OpTypeImage;
- const static SPIRVWord FixedWC = 9;
- SPIRVTypeImage(SPIRVModule *M, SPIRVId TheId, SPIRVId TheSampledType,
- const SPIRVTypeImageDescriptor &TheDesc)
- :SPIRVType(M, FixedWC, OC, TheId), SampledType(TheSampledType),
- Desc(TheDesc){
- validate();
- }
- SPIRVTypeImage(SPIRVModule *M, SPIRVId TheId, SPIRVId TheSampledType,
- const SPIRVTypeImageDescriptor &TheDesc, SPIRVAccessQualifierKind TheAcc)
- :SPIRVType(M, FixedWC + 1, OC, TheId), SampledType(TheSampledType),
- Desc(TheDesc){
- Acc.push_back(TheAcc);
- validate();
- }
- SPIRVTypeImage():SPIRVType(OC), SampledType(SPIRVID_INVALID), Desc(){
- }
- const SPIRVTypeImageDescriptor &getDescriptor()const {
- return Desc;
- }
- bool isOCLImage()const {
- return Desc.Sampled == 0 && Desc.Format == 0;
- }
- bool hasAccessQualifier() const { return !Acc.empty();}
- SPIRVAccessQualifierKind getAccessQualifier() const {
- assert(hasAccessQualifier());
- return Acc[0];
- }
- SPIRVCapVec getRequiredCapability() const {
- SPIRVCapVec CV;
- CV.push_back(CapabilityImageBasic);
+//===- SPIRVType.h - Class to represent a SPIR-V Type -----------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines the types defined in SPIRV spec with op codes. +/// +/// The name of the SPIR-V types follow the op code name in the spec, e.g. +/// SPIR-V type with op code name OpTypeInt is named as SPIRVTypeInt. This is +/// for readability and ease of using macro to handle types. +/// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVTYPE_HPP_ +#define SPIRVTYPE_HPP_ + +#include "SPIRVEntry.h" +#include "SPIRVStream.h" + +#include <cassert> +#include <tuple> +#include <vector> +#include <map> +#include <iostream> + +namespace SPIRV{ + +class SPIRVType: public SPIRVEntry { +public: + // Complete constructor + SPIRVType(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, + SPIRVId TheId) + :SPIRVEntry(M, TheWordCount, TheOpCode, TheId){} + // Incomplete constructor + SPIRVType(Op TheOpCode):SPIRVEntry(TheOpCode){} + + SPIRVType *getArrayElementType() const; + uint64_t getArrayLength() const; + unsigned getBitWidth() const; + unsigned getFloatBitWidth() const; + SPIRVType *getFunctionReturnType() const; + unsigned getIntegerBitWidth() const; + SPIRVType *getPointerElementType() const; + SPIRVStorageClassKind getPointerStorageClass() const; + SPIRVType *getStructMemberType(size_t) const; + SPIRVWord getStructMemberCount() const; + SPIRVWord getVectorComponentCount() const; + SPIRVType *getVectorComponentType() const; + + bool isTypeVoid() const; + bool isTypeArray() const; + bool isTypeBool() const; + bool isTypeComposite() const; + bool isTypeEvent() const; + bool isTypeDeviceEvent() const; + bool isTypeReserveId() const; + bool isTypeFloat(unsigned Bits = 0) const; + bool isTypeImage() const; + bool isTypeOCLImage() const; + bool isTypePipe()const; + bool isTypePipeStorage() const; + bool isTypeInt(unsigned Bits = 0) const; + bool isTypeOpaque() const; + bool isTypePointer() const; + bool isTypeSampler() const; + bool isTypeStruct() const; + bool isTypeVector() const; + bool isTypeVectorInt() const; + bool isTypeVectorFloat() const; + bool isTypeVectorBool() const; + bool isTypeVectorOrScalarInt() const; + bool isTypeVectorOrScalarFloat() const; + bool isTypeVectorOrScalarBool() const; +}; + +class SPIRVTypeVoid:public SPIRVType { +public: + // Complete constructor + SPIRVTypeVoid(SPIRVModule *M, SPIRVId TheId) + :SPIRVType(M, 2, OpTypeVoid, TheId){} + // Incomplete constructor + SPIRVTypeVoid():SPIRVType(OpTypeVoid){} +protected: + _SPIRV_DEF_ENCDEC1(Id) +}; + +class SPIRVTypeBool:public SPIRVType { +public: + // Complete constructor + SPIRVTypeBool(SPIRVModule *M, SPIRVId TheId) + :SPIRVType(M, 2, OpTypeBool, TheId){} + // Incomplete constructor + SPIRVTypeBool():SPIRVType(OpTypeBool){} +protected: + _SPIRV_DEF_ENCDEC1(Id) +}; + +class SPIRVTypeInt:public SPIRVType { +public: + static const Op OC = OpTypeInt; + // Complete constructor + SPIRVTypeInt(SPIRVModule *M, SPIRVId TheId, unsigned TheBitWidth, + bool ItIsSigned) + :SPIRVType(M, 4, OC , TheId), BitWidth(TheBitWidth), + IsSigned(ItIsSigned){ + validate(); + } + // Incomplete constructor + SPIRVTypeInt():SPIRVType(OC), BitWidth(0), IsSigned(false){} + + unsigned getBitWidth() const { return BitWidth;} + bool isSigned() const { return IsSigned;} + SPIRVCapVec getRequiredCapability() const { + SPIRVCapVec CV; + switch (BitWidth) { + case 8: + CV.push_back(CapabilityInt8); + break; + case 16: + CV.push_back(CapabilityInt16); + break; + case 64: + CV.push_back(CapabilityInt64); + break; + default: + break; + } + return std::move(CV); + } + +protected: + _SPIRV_DEF_ENCDEC3(Id, BitWidth, IsSigned) + void validate()const { + SPIRVEntry::validate(); + assert(BitWidth > 1 && BitWidth <= 64 && "Invalid bit width"); + } +private: + unsigned BitWidth; // Bit width + bool IsSigned; // Whether it is signed +}; + +class SPIRVTypeFloat:public SPIRVType { +public: + static const Op OC = OpTypeFloat; + // Complete constructor + SPIRVTypeFloat(SPIRVModule *M, SPIRVId TheId, unsigned TheBitWidth) + :SPIRVType(M, 3, OC, TheId), BitWidth(TheBitWidth){} + // Incomplete constructor + SPIRVTypeFloat():SPIRVType(OC), BitWidth(0){} + + unsigned getBitWidth() const { return BitWidth;} + + SPIRVCapVec getRequiredCapability() const { + SPIRVCapVec CV; + if (isTypeFloat(16)) { + CV.push_back(CapabilityFloat16Buffer); + auto extensions = getModule()->getExtension(); + if (std::any_of(extensions.begin(), extensions.end(), + [](const std::string &I){return I == "cl_khr_fp16";})) + CV.push_back(CapabilityFloat16); + } + else if (isTypeFloat(64)) + CV.push_back(CapabilityFloat64); + return std::move(CV); + } + + +protected: + _SPIRV_DEF_ENCDEC2(Id, BitWidth) + void validate()const { + SPIRVEntry::validate(); + assert(BitWidth >= 16 && BitWidth <= 64 && "Invalid bit width"); + } +private: + unsigned BitWidth; // Bit width +}; + +class SPIRVTypePointer:public SPIRVType { +public: + // Complete constructor + SPIRVTypePointer(SPIRVModule *M, SPIRVId TheId, + SPIRVStorageClassKind TheStorageClass, + SPIRVType *ElementType) + :SPIRVType(M, 4, OpTypePointer, TheId), ElemStorageClass(TheStorageClass), + ElemTypeId(ElementType->getId()){ + validate(); + } + // Incomplete constructor + SPIRVTypePointer():SPIRVType(OpTypePointer), + ElemStorageClass(StorageClassFunction), + ElemTypeId(0){} + + SPIRVType *getElementType() const { + return static_cast<SPIRVType *>(getEntry(ElemTypeId)); + } + SPIRVStorageClassKind getStorageClass() const { return ElemStorageClass;} + SPIRVCapVec getRequiredCapability() const { + auto Cap = getVec(CapabilityAddresses); + if (getElementType()->isTypeFloat(16)) + Cap.push_back(CapabilityFloat16Buffer); + auto C = getCapability(ElemStorageClass); + Cap.insert(Cap.end(), C.begin(), C.end()); + return Cap; + } + virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { + return std::vector<SPIRVEntry*>(1, getEntry(ElemTypeId)); + } + +protected: + _SPIRV_DEF_ENCDEC3(Id, ElemStorageClass, ElemTypeId) + void validate()const { + SPIRVEntry::validate(); + assert(isValid(ElemStorageClass)); + } +private: + SPIRVStorageClassKind ElemStorageClass; // Storage Class + SPIRVId ElemTypeId; +}; + +class SPIRVTypeForwardPointer : public SPIRVEntryNoId<OpTypeForwardPointer> { +public: + SPIRVTypeForwardPointer(SPIRVModule *M, SPIRVTypePointer *Pointer, + SPIRVStorageClassKind SC) + : SPIRVEntryNoId(M, 3), Pointer(Pointer), SC(SC) {} + + SPIRVTypeForwardPointer() + : Pointer(nullptr), SC(StorageClassUniformConstant) {} + + SPIRVTypePointer *getPointer() const { return Pointer; } + _SPIRV_DCL_ENCDEC +private: + SPIRVTypePointer *Pointer; + SPIRVStorageClassKind SC; +}; + +class SPIRVTypeVector:public SPIRVType { +public: + // Complete constructor + SPIRVTypeVector(SPIRVModule *M, SPIRVId TheId, SPIRVType *TheCompType, + SPIRVWord TheCompCount) + :SPIRVType(M, 4, OpTypeVector, TheId), CompType(TheCompType), + CompCount(TheCompCount){ + validate(); + } + // Incomplete constructor + SPIRVTypeVector():SPIRVType(OpTypeVector), CompType(nullptr), + CompCount(0){} + + SPIRVType *getComponentType() const { return CompType;} + SPIRVWord getComponentCount() const { return CompCount;} + bool isValidIndex(SPIRVWord Index) const { return Index < CompCount;} + SPIRVCapVec getRequiredCapability() const { + SPIRVCapVec V(getComponentType()->getRequiredCapability()); + // Even though the capability name is "Vector16", it describes + // usage of 8-component or 16-component vectors. + if (CompCount >= 8) + V.push_back(CapabilityVector16); + return std::move(V); + } + + virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { + return std::vector<SPIRVEntry*>(1, CompType); + } + +protected: + _SPIRV_DEF_ENCDEC3(Id, CompType, CompCount) + void validate()const { + SPIRVEntry::validate(); + CompType->validate(); + assert(CompCount == 2 || CompCount == 3 || CompCount == 4 || + CompCount == 8 || CompCount == 16); + } +private: + SPIRVType *CompType; // Component Type + SPIRVWord CompCount; // Component Count +}; + +class SPIRVConstant; +class SPIRVTypeArray:public SPIRVType { +public: + // Complete constructor + SPIRVTypeArray(SPIRVModule *M, SPIRVId TheId, SPIRVType *TheElemType, + SPIRVConstant* TheLength); + // Incomplete constructor + SPIRVTypeArray():SPIRVType(OpTypeArray), ElemType(nullptr), + Length(SPIRVID_INVALID){} + + SPIRVType *getElementType() const { return ElemType;} + SPIRVConstant *getLength() const; + SPIRVCapVec getRequiredCapability() const { + return std::move(getElementType()->getRequiredCapability()); + } + virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { + std::vector<SPIRVEntry*> Operands(2, ElemType); + Operands[1] = (SPIRVEntry*)getLength(); + return Operands; + } + + +protected: + _SPIRV_DCL_ENCDEC + void validate()const; +private: + SPIRVType *ElemType; // Element Type + SPIRVId Length; // Array Length +}; + +class SPIRVTypeOpaque:public SPIRVType { +public: + // Complete constructor + SPIRVTypeOpaque(SPIRVModule *M, SPIRVId TheId, const std::string& TheName) + :SPIRVType(M, 2 + getSizeInWords(TheName), OpTypeOpaque, TheId) { + Name = TheName; + validate(); + } + // Incomplete constructor + SPIRVTypeOpaque():SPIRVType(OpTypeOpaque){} + +protected: + _SPIRV_DEF_ENCDEC2(Id, Name) + void validate()const { + SPIRVEntry::validate(); + } +}; + +struct SPIRVTypeImageDescriptor { + SPIRVImageDimKind Dim; + SPIRVWord Depth; + SPIRVWord Arrayed; + SPIRVWord MS; + SPIRVWord Sampled; + SPIRVWord Format; + static std::tuple<std::tuple<SPIRVImageDimKind, SPIRVWord, SPIRVWord, SPIRVWord, + SPIRVWord>, SPIRVWord> + getAsTuple (const SPIRVTypeImageDescriptor &Desc) { + return std::make_tuple(std::make_tuple(Desc.Dim, Desc.Depth, Desc.Arrayed, + Desc.MS, Desc.Sampled), Desc.Format); + } + SPIRVTypeImageDescriptor():Dim(Dim1D), Depth(0), Arrayed(0), + MS(0), Sampled(0), Format(0){} + SPIRVTypeImageDescriptor(SPIRVImageDimKind Dim, SPIRVWord Cont, SPIRVWord Arr, + SPIRVWord Comp, SPIRVWord Mult, SPIRVWord F):Dim(Dim), Depth(Cont), + Arrayed(Arr), MS(Comp), Sampled(Mult), Format(F){} +}; + +template<> inline void +SPIRVMap<std::string, SPIRVTypeImageDescriptor>::init() { +#define _SPIRV_OP(x,...) {SPIRVTypeImageDescriptor S(__VA_ARGS__); \ + add(#x, S);} +_SPIRV_OP(image1d_t, Dim1D, 0, 0, 0, 0, 0) +_SPIRV_OP(image1d_buffer_t, DimBuffer, 0, 0, 0, 0, 0) +_SPIRV_OP(image1d_array_t, Dim1D, 0, 1, 0, 0, 0) +_SPIRV_OP(image2d_t, Dim2D, 0, 0, 0, 0, 0) +_SPIRV_OP(image2d_array_t, Dim2D, 0, 1, 0, 0, 0) +_SPIRV_OP(image2d_depth_t, Dim2D, 1, 0, 0, 0, 0) +_SPIRV_OP(image2d_array_depth_t, Dim2D, 1, 1, 0, 0, 0) +_SPIRV_OP(image2d_msaa_t, Dim2D, 0, 0, 1, 0, 0) +_SPIRV_OP(image2d_array_msaa_t, Dim2D, 0, 1, 1, 0, 0) +_SPIRV_OP(image2d_msaa_depth_t, Dim2D, 1, 0, 1, 0, 0) +_SPIRV_OP(image2d_array_msaa_depth_t, Dim2D, 1, 1, 1, 0, 0) +_SPIRV_OP(image3d_t, Dim3D, 0, 0, 0, 0, 0) +#undef _SPIRV_OP +} +typedef SPIRVMap<std::string, SPIRVTypeImageDescriptor> + OCLSPIRVImageTypeMap; + +// Comparision function required to use the struct as map key. +inline bool +operator<(const SPIRVTypeImageDescriptor &A, + const SPIRVTypeImageDescriptor &B){ + return SPIRVTypeImageDescriptor::getAsTuple(A) < + SPIRVTypeImageDescriptor::getAsTuple(B); +} + +class SPIRVTypeImage:public SPIRVType { +public: + const static Op OC = OpTypeImage; + const static SPIRVWord FixedWC = 9; + SPIRVTypeImage(SPIRVModule *M, SPIRVId TheId, SPIRVId TheSampledType, + const SPIRVTypeImageDescriptor &TheDesc) + :SPIRVType(M, FixedWC, OC, TheId), SampledType(TheSampledType), + Desc(TheDesc){ + validate(); + } + SPIRVTypeImage(SPIRVModule *M, SPIRVId TheId, SPIRVId TheSampledType, + const SPIRVTypeImageDescriptor &TheDesc, SPIRVAccessQualifierKind TheAcc) + :SPIRVType(M, FixedWC + 1, OC, TheId), SampledType(TheSampledType), + Desc(TheDesc){ + Acc.push_back(TheAcc); + validate(); + } + SPIRVTypeImage():SPIRVType(OC), SampledType(SPIRVID_INVALID), Desc(){ + } + const SPIRVTypeImageDescriptor &getDescriptor()const { + return Desc; + } + bool isOCLImage()const { + return Desc.Sampled == 0 && Desc.Format == 0; + } + bool hasAccessQualifier() const { return !Acc.empty();} + SPIRVAccessQualifierKind getAccessQualifier() const { + assert(hasAccessQualifier()); + return Acc[0]; + } + SPIRVCapVec getRequiredCapability() const { + SPIRVCapVec CV; + CV.push_back(CapabilityImageBasic); if (Desc.Dim == SPIRVImageDimKind::Dim1D) CV.push_back(CapabilitySampled1D); else if (Desc.Dim == SPIRVImageDimKind::DimBuffer) CV.push_back(CapabilitySampledBuffer); - if (Acc.size() > 0 && Acc[0] == AccessQualifierReadWrite)
- CV.push_back(CapabilityImageReadWrite);
- if (Desc.MS)
- CV.push_back(CapabilityImageMipmap);
- return CV;
- }
- SPIRVType *getSampledType() const {
- return get<SPIRVType>(SampledType);
- }
-
- virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const {
- return std::vector<SPIRVEntry*>(1, get<SPIRVType>(SampledType));
- }
-
-protected:
- _SPIRV_DEF_ENCDEC9(Id, SampledType, Desc.Dim, Desc.Depth,
- Desc.Arrayed, Desc.MS, Desc.Sampled, Desc.Format, Acc)
- // The validation assumes OpenCL image or sampler type.
- void validate()const {
- assert(OpCode == OC);
- assert(WordCount == FixedWC + Acc.size());
- assert(SampledType != SPIRVID_INVALID && "Invalid sampled type");
- assert(Desc.Dim <= 5);
- assert(Desc.Depth <= 1);
- assert(Desc.Arrayed <= 1);
- assert(Desc.MS <= 1);
- assert(Desc.Sampled == 0); // For OCL only
- assert(Desc.Format == 0); // For OCL only
- assert(Acc.size() <= 1);
- }
- void setWordCount(SPIRVWord TheWC) {
- WordCount = TheWC;
- Acc.resize(WordCount - FixedWC);
- }
-private:
- SPIRVId SampledType;
- SPIRVTypeImageDescriptor Desc;
- std::vector<SPIRVAccessQualifierKind> Acc;
-};
-
-class SPIRVTypeSampler:public SPIRVType {
-public:
- const static Op OC = OpTypeSampler;
- const static SPIRVWord FixedWC = 2;
- SPIRVTypeSampler(SPIRVModule *M, SPIRVId TheId)
- :SPIRVType(M, FixedWC, OC, TheId){
- validate();
- }
- SPIRVTypeSampler():SPIRVType(OC){
- }
-protected:
- _SPIRV_DEF_ENCDEC1(Id)
- void validate()const {
- assert(OpCode == OC);
- assert(WordCount == FixedWC);
- }
-};
-
-class SPIRVTypeSampledImage:public SPIRVType {
-public:
- const static Op OC = OpTypeSampledImage;
- const static SPIRVWord FixedWC = 3;
- SPIRVTypeSampledImage(SPIRVModule *M, SPIRVId TheId, SPIRVTypeImage *TheImgTy)
- :SPIRVType(M, FixedWC, OC, TheId), ImgTy(TheImgTy){
- validate();
- }
- SPIRVTypeSampledImage():SPIRVType(OC), ImgTy(nullptr){
- }
-
- const SPIRVTypeImage *getImageType() const {
- return ImgTy;
- }
-
- void setImageType(SPIRVTypeImage *TheImgTy) {
- ImgTy = TheImgTy;
- }
-
- virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const {
- return std::vector<SPIRVEntry*>(1, ImgTy);
- }
-
-protected:
- SPIRVTypeImage *ImgTy;
- _SPIRV_DEF_ENCDEC2(Id, ImgTy)
- void validate()const {
- assert(OpCode == OC);
- assert(WordCount == FixedWC);
- assert(ImgTy && ImgTy->isTypeImage());
- }
-};
-
-class SPIRVTypePipeStorage :public SPIRVType {
-public:
- const static Op OC = OpTypePipeStorage;
- const static SPIRVWord FixedWC = 2;
- SPIRVTypePipeStorage(SPIRVModule *M, SPIRVId TheId)
- :SPIRVType(M, FixedWC, OC, TheId){
- validate();
- }
- SPIRVTypePipeStorage() :SPIRVType(OC){
- }
-protected:
- _SPIRV_DEF_ENCDEC1(Id)
- void validate()const {
- assert(OpCode == OC);
- assert(WordCount == FixedWC);
- }
-};
-
-class SPIRVTypeStruct : public SPIRVType {
-public:
- // Complete constructor
- SPIRVTypeStruct(SPIRVModule *M, SPIRVId TheId,
- const std::vector<SPIRVType *> &TheMemberTypes,
- const std::string &TheName)
- : SPIRVType(M, 2 + TheMemberTypes.size(), OpTypeStruct, TheId) {
- MemberTypeIdVec.resize(TheMemberTypes.size());
- for (auto &t : TheMemberTypes)
- MemberTypeIdVec.push_back(t->getId());
- Name = TheName;
- validate();
- }
- SPIRVTypeStruct(SPIRVModule *M, SPIRVId TheId, unsigned NumMembers,
- const std::string &TheName)
- : SPIRVType(M, 2 + NumMembers, OpTypeStruct, TheId) {
- Name = TheName;
- validate();
- MemberTypeIdVec.resize(NumMembers);
- }
- // Incomplete constructor
- SPIRVTypeStruct() : SPIRVType(OpTypeStruct) {}
-
- SPIRVWord getMemberCount() const { return MemberTypeIdVec.size(); }
- SPIRVType *getMemberType(size_t I) const {
- return static_cast<SPIRVType *>(getEntry(MemberTypeIdVec[I]));
- }
- void setMemberType(size_t I, SPIRVType *Ty) { MemberTypeIdVec[I] = Ty->getId(); }
-
- bool isPacked() const;
- void setPacked(bool Packed);
-
- void setWordCount(SPIRVWord WordCount) {
- SPIRVType::setWordCount(WordCount);
- MemberTypeIdVec.resize(WordCount - 2);
- }
-
- virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const {
- std::vector<SPIRVEntry*> Operands(MemberTypeIdVec.size());
- for (size_t I = 0, E = MemberTypeIdVec.size(); I < E; ++I)
- Operands[I] = getEntry(MemberTypeIdVec[I]);
- return Operands;
- }
-
-protected:
- _SPIRV_DEF_ENCDEC2(Id, MemberTypeIdVec)
-
- void validate() const { SPIRVEntry::validate(); }
-
-private:
- std::vector<SPIRVId> MemberTypeIdVec; // Member Type Ids
-};
-
-class SPIRVTypeFunction:public SPIRVType {
-public:
- // Complete constructor
- SPIRVTypeFunction(SPIRVModule *M, SPIRVId TheId, SPIRVType *TheReturnType,
- const std::vector<SPIRVType *> &TheParameterTypes)
- :SPIRVType(M, 3 + TheParameterTypes.size(), OpTypeFunction, TheId),
- ReturnType(TheReturnType), ParamTypeVec(TheParameterTypes){
- validate();
- }
- // Incomplete constructor
- SPIRVTypeFunction():SPIRVType(OpTypeFunction), ReturnType(NULL){}
-
- SPIRVType *getReturnType() const { return ReturnType;}
- SPIRVWord getNumParameters() const { return ParamTypeVec.size();}
- SPIRVType *getParameterType(unsigned I) const { return ParamTypeVec[I];}
- virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const {
- std::vector<SPIRVEntry*> Operands( 1 + ParamTypeVec.size(), ReturnType);
- std::copy(ParamTypeVec.begin(), ParamTypeVec.end(), ++Operands.begin());
- return Operands;
- }
-
-protected:
- _SPIRV_DEF_ENCDEC3(Id, ReturnType, ParamTypeVec)
- void setWordCount(SPIRVWord WordCount) {
- SPIRVType::setWordCount(WordCount);
- ParamTypeVec.resize(WordCount - 3);
- }
- void validate()const {
- SPIRVEntry::validate();
- ReturnType->validate();
- for (auto T:ParamTypeVec)
- T->validate();
- }
-private:
- SPIRVType *ReturnType; // Return Type
- std::vector<SPIRVType *> ParamTypeVec; // Parameter Types
-};
-
-class SPIRVTypeOpaqueGeneric:public SPIRVType {
-public:
- // Complete constructor
- SPIRVTypeOpaqueGeneric(Op TheOpCode, SPIRVModule *M, SPIRVId TheId)
- :SPIRVType(M, 2, TheOpCode, TheId){
- validate();
- }
-
- // Incomplete constructor
- SPIRVTypeOpaqueGeneric(Op TheOpCode):SPIRVType(TheOpCode),
- Opn(SPIRVID_INVALID) {}
-
- SPIRVValue *getOperand() {
- return getValue(Opn);
- }
-protected:
- _SPIRV_DEF_ENCDEC1(Id)
- void validate()const {
- SPIRVEntry::validate();
- }
- SPIRVId Opn;
-};
-
-template<Op TheOpCode>
-class SPIRVOpaqueGenericType:public SPIRVTypeOpaqueGeneric {
-public:
- // Complete constructor
- SPIRVOpaqueGenericType(SPIRVModule *M, SPIRVId TheId)
- :SPIRVTypeOpaqueGeneric(TheOpCode, M, TheId){}
- // Incomplete constructor
- SPIRVOpaqueGenericType():SPIRVTypeOpaqueGeneric(TheOpCode){}
-};
-
-#define _SPIRV_OP(x) typedef SPIRVOpaqueGenericType<OpType##x> SPIRVType##x;
-_SPIRV_OP(Event)
-_SPIRV_OP(ReserveId)
-#undef _SPIRV_OP
-
-class SPIRVTypeDeviceEvent : public SPIRVType {
-public:
- // Complete constructor
- SPIRVTypeDeviceEvent(SPIRVModule *M, SPIRVId TheId)
- : SPIRVType(M, 2, OpTypeDeviceEvent, TheId) {
- validate();
- }
-
- // Incomplete constructor
- SPIRVTypeDeviceEvent() : SPIRVType(OpTypeDeviceEvent) {}
-
- SPIRVCapVec getRequiredCapability() const {
- return getVec(CapabilityDeviceEnqueue);
- }
-
-protected:
- _SPIRV_DEF_ENCDEC1(Id)
- void validate() const { SPIRVEntry::validate(); }
-};
-
-class SPIRVTypeQueue : public SPIRVType {
-public:
- // Complete constructor
- SPIRVTypeQueue(SPIRVModule *M, SPIRVId TheId)
- : SPIRVType(M, 2, OpTypeQueue, TheId) {
- validate();
- }
-
- // Incomplete constructor
- SPIRVTypeQueue() : SPIRVType(OpTypeQueue) {}
-
- SPIRVCapVec getRequiredCapability() const {
- return getVec(CapabilityDeviceEnqueue);
- }
-
-protected:
- _SPIRV_DEF_ENCDEC1(Id)
-};
-
-class SPIRVTypePipe :public SPIRVType {
-public:
- // Complete constructor
- SPIRVTypePipe(SPIRVModule *M, SPIRVId TheId,
- SPIRVAccessQualifierKind AccessQual = AccessQualifierReadOnly)
- :SPIRVType(M, 3, OpTypePipe, TheId),
- AccessQualifier(AccessQual){
- validate();
- }
-
- // Incomplete constructor
- SPIRVTypePipe() :SPIRVType(OpTypePipe),
- AccessQualifier(AccessQualifierReadOnly){}
-
- SPIRVAccessQualifierKind getAccessQualifier() const {
- return AccessQualifier;
- }
- void setPipeAcessQualifier(SPIRVAccessQualifierKind AccessQual) {
- AccessQualifier = AccessQual;
- assert(isValid(AccessQualifier));
- }
- SPIRVCapVec getRequiredCapability() const {
- return getVec(CapabilityPipes);
- }
-protected:
- _SPIRV_DEF_ENCDEC2(Id, AccessQualifier)
- void validate()const {
- SPIRVEntry::validate();
- }
-private:
- SPIRVAccessQualifierKind AccessQualifier; // Access Qualifier
-};
-
-template<typename T2, typename T1>
-bool
-isType(const T1 *Ty, unsigned Bits = 0) {
- bool Is = Ty->getOpCode() == T2::OC;
- if (!Is)
- return false;
- if (Bits == 0)
- return true;
- return static_cast<const T2*>(Ty)->getBitWidth() == Bits;
-}
-
-}
-#endif // SPIRVTYPE_HPP_
+ if (Acc.size() > 0 && Acc[0] == AccessQualifierReadWrite) + CV.push_back(CapabilityImageReadWrite); + if (Desc.MS) + CV.push_back(CapabilityImageMipmap); + return CV; + } + SPIRVType *getSampledType() const { + return get<SPIRVType>(SampledType); + } + + virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { + return std::vector<SPIRVEntry*>(1, get<SPIRVType>(SampledType)); + } + +protected: + _SPIRV_DEF_ENCDEC9(Id, SampledType, Desc.Dim, Desc.Depth, + Desc.Arrayed, Desc.MS, Desc.Sampled, Desc.Format, Acc) + // The validation assumes OpenCL image or sampler type. + void validate()const { + assert(OpCode == OC); + assert(WordCount == FixedWC + Acc.size()); + assert(SampledType != SPIRVID_INVALID && "Invalid sampled type"); + assert(Desc.Dim <= 5); + assert(Desc.Depth <= 1); + assert(Desc.Arrayed <= 1); + assert(Desc.MS <= 1); + assert(Desc.Sampled == 0); // For OCL only + assert(Desc.Format == 0); // For OCL only + assert(Acc.size() <= 1); + } + void setWordCount(SPIRVWord TheWC) { + WordCount = TheWC; + Acc.resize(WordCount - FixedWC); + } +private: + SPIRVId SampledType; + SPIRVTypeImageDescriptor Desc; + std::vector<SPIRVAccessQualifierKind> Acc; +}; + +class SPIRVTypeSampler:public SPIRVType { +public: + const static Op OC = OpTypeSampler; + const static SPIRVWord FixedWC = 2; + SPIRVTypeSampler(SPIRVModule *M, SPIRVId TheId) + :SPIRVType(M, FixedWC, OC, TheId){ + validate(); + } + SPIRVTypeSampler():SPIRVType(OC){ + } +protected: + _SPIRV_DEF_ENCDEC1(Id) + void validate()const { + assert(OpCode == OC); + assert(WordCount == FixedWC); + } +}; + +class SPIRVTypeSampledImage:public SPIRVType { +public: + const static Op OC = OpTypeSampledImage; + const static SPIRVWord FixedWC = 3; + SPIRVTypeSampledImage(SPIRVModule *M, SPIRVId TheId, SPIRVTypeImage *TheImgTy) + :SPIRVType(M, FixedWC, OC, TheId), ImgTy(TheImgTy){ + validate(); + } + SPIRVTypeSampledImage():SPIRVType(OC), ImgTy(nullptr){ + } + + const SPIRVTypeImage *getImageType() const { + return ImgTy; + } + + void setImageType(SPIRVTypeImage *TheImgTy) { + ImgTy = TheImgTy; + } + + virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { + return std::vector<SPIRVEntry*>(1, ImgTy); + } + +protected: + SPIRVTypeImage *ImgTy; + _SPIRV_DEF_ENCDEC2(Id, ImgTy) + void validate()const { + assert(OpCode == OC); + assert(WordCount == FixedWC); + assert(ImgTy && ImgTy->isTypeImage()); + } +}; + +class SPIRVTypePipeStorage :public SPIRVType { +public: + const static Op OC = OpTypePipeStorage; + const static SPIRVWord FixedWC = 2; + SPIRVTypePipeStorage(SPIRVModule *M, SPIRVId TheId) + :SPIRVType(M, FixedWC, OC, TheId){ + validate(); + } + SPIRVTypePipeStorage() :SPIRVType(OC){ + } +protected: + _SPIRV_DEF_ENCDEC1(Id) + void validate()const { + assert(OpCode == OC); + assert(WordCount == FixedWC); + } +}; + +class SPIRVTypeStruct : public SPIRVType { +public: + // Complete constructor + SPIRVTypeStruct(SPIRVModule *M, SPIRVId TheId, + const std::vector<SPIRVType *> &TheMemberTypes, + const std::string &TheName) + : SPIRVType(M, 2 + TheMemberTypes.size(), OpTypeStruct, TheId) { + MemberTypeIdVec.resize(TheMemberTypes.size()); + for (auto &t : TheMemberTypes) + MemberTypeIdVec.push_back(t->getId()); + Name = TheName; + validate(); + } + SPIRVTypeStruct(SPIRVModule *M, SPIRVId TheId, unsigned NumMembers, + const std::string &TheName) + : SPIRVType(M, 2 + NumMembers, OpTypeStruct, TheId) { + Name = TheName; + validate(); + MemberTypeIdVec.resize(NumMembers); + } + // Incomplete constructor + SPIRVTypeStruct() : SPIRVType(OpTypeStruct) {} + + SPIRVWord getMemberCount() const { return MemberTypeIdVec.size(); } + SPIRVType *getMemberType(size_t I) const { + return static_cast<SPIRVType *>(getEntry(MemberTypeIdVec[I])); + } + void setMemberType(size_t I, SPIRVType *Ty) { MemberTypeIdVec[I] = Ty->getId(); } + + bool isPacked() const; + void setPacked(bool Packed); + + void setWordCount(SPIRVWord WordCount) { + SPIRVType::setWordCount(WordCount); + MemberTypeIdVec.resize(WordCount - 2); + } + + virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { + std::vector<SPIRVEntry*> Operands(MemberTypeIdVec.size()); + for (size_t I = 0, E = MemberTypeIdVec.size(); I < E; ++I) + Operands[I] = getEntry(MemberTypeIdVec[I]); + return Operands; + } + +protected: + _SPIRV_DEF_ENCDEC2(Id, MemberTypeIdVec) + + void validate() const { SPIRVEntry::validate(); } + +private: + std::vector<SPIRVId> MemberTypeIdVec; // Member Type Ids +}; + +class SPIRVTypeFunction:public SPIRVType { +public: + // Complete constructor + SPIRVTypeFunction(SPIRVModule *M, SPIRVId TheId, SPIRVType *TheReturnType, + const std::vector<SPIRVType *> &TheParameterTypes) + :SPIRVType(M, 3 + TheParameterTypes.size(), OpTypeFunction, TheId), + ReturnType(TheReturnType), ParamTypeVec(TheParameterTypes){ + validate(); + } + // Incomplete constructor + SPIRVTypeFunction():SPIRVType(OpTypeFunction), ReturnType(NULL){} + + SPIRVType *getReturnType() const { return ReturnType;} + SPIRVWord getNumParameters() const { return ParamTypeVec.size();} + SPIRVType *getParameterType(unsigned I) const { return ParamTypeVec[I];} + virtual std::vector<SPIRVEntry*> getNonLiteralOperands() const { + std::vector<SPIRVEntry*> Operands( 1 + ParamTypeVec.size(), ReturnType); + std::copy(ParamTypeVec.begin(), ParamTypeVec.end(), ++Operands.begin()); + return Operands; + } + +protected: + _SPIRV_DEF_ENCDEC3(Id, ReturnType, ParamTypeVec) + void setWordCount(SPIRVWord WordCount) { + SPIRVType::setWordCount(WordCount); + ParamTypeVec.resize(WordCount - 3); + } + void validate()const { + SPIRVEntry::validate(); + ReturnType->validate(); + for (auto T:ParamTypeVec) + T->validate(); + } +private: + SPIRVType *ReturnType; // Return Type + std::vector<SPIRVType *> ParamTypeVec; // Parameter Types +}; + +class SPIRVTypeOpaqueGeneric:public SPIRVType { +public: + // Complete constructor + SPIRVTypeOpaqueGeneric(Op TheOpCode, SPIRVModule *M, SPIRVId TheId) + :SPIRVType(M, 2, TheOpCode, TheId){ + validate(); + } + + // Incomplete constructor + SPIRVTypeOpaqueGeneric(Op TheOpCode):SPIRVType(TheOpCode), + Opn(SPIRVID_INVALID) {} + + SPIRVValue *getOperand() { + return getValue(Opn); + } +protected: + _SPIRV_DEF_ENCDEC1(Id) + void validate()const { + SPIRVEntry::validate(); + } + SPIRVId Opn; +}; + +template<Op TheOpCode> +class SPIRVOpaqueGenericType:public SPIRVTypeOpaqueGeneric { +public: + // Complete constructor + SPIRVOpaqueGenericType(SPIRVModule *M, SPIRVId TheId) + :SPIRVTypeOpaqueGeneric(TheOpCode, M, TheId){} + // Incomplete constructor + SPIRVOpaqueGenericType():SPIRVTypeOpaqueGeneric(TheOpCode){} +}; + +#define _SPIRV_OP(x) typedef SPIRVOpaqueGenericType<OpType##x> SPIRVType##x; +_SPIRV_OP(Event) +_SPIRV_OP(ReserveId) +#undef _SPIRV_OP + +class SPIRVTypeDeviceEvent : public SPIRVType { +public: + // Complete constructor + SPIRVTypeDeviceEvent(SPIRVModule *M, SPIRVId TheId) + : SPIRVType(M, 2, OpTypeDeviceEvent, TheId) { + validate(); + } + + // Incomplete constructor + SPIRVTypeDeviceEvent() : SPIRVType(OpTypeDeviceEvent) {} + + SPIRVCapVec getRequiredCapability() const { + return getVec(CapabilityDeviceEnqueue); + } + +protected: + _SPIRV_DEF_ENCDEC1(Id) + void validate() const { SPIRVEntry::validate(); } +}; + +class SPIRVTypeQueue : public SPIRVType { +public: + // Complete constructor + SPIRVTypeQueue(SPIRVModule *M, SPIRVId TheId) + : SPIRVType(M, 2, OpTypeQueue, TheId) { + validate(); + } + + // Incomplete constructor + SPIRVTypeQueue() : SPIRVType(OpTypeQueue) {} + + SPIRVCapVec getRequiredCapability() const { + return getVec(CapabilityDeviceEnqueue); + } + +protected: + _SPIRV_DEF_ENCDEC1(Id) +}; + +class SPIRVTypePipe :public SPIRVType { +public: + // Complete constructor + SPIRVTypePipe(SPIRVModule *M, SPIRVId TheId, + SPIRVAccessQualifierKind AccessQual = AccessQualifierReadOnly) + :SPIRVType(M, 3, OpTypePipe, TheId), + AccessQualifier(AccessQual){ + validate(); + } + + // Incomplete constructor + SPIRVTypePipe() :SPIRVType(OpTypePipe), + AccessQualifier(AccessQualifierReadOnly){} + + SPIRVAccessQualifierKind getAccessQualifier() const { + return AccessQualifier; + } + void setPipeAcessQualifier(SPIRVAccessQualifierKind AccessQual) { + AccessQualifier = AccessQual; + assert(isValid(AccessQualifier)); + } + SPIRVCapVec getRequiredCapability() const { + return getVec(CapabilityPipes); + } +protected: + _SPIRV_DEF_ENCDEC2(Id, AccessQualifier) + void validate()const { + SPIRVEntry::validate(); + } +private: + SPIRVAccessQualifierKind AccessQualifier; // Access Qualifier +}; + +template<typename T2, typename T1> +bool +isType(const T1 *Ty, unsigned Bits = 0) { + bool Is = Ty->getOpCode() == T2::OC; + if (!Is) + return false; + if (Bits == 0) + return true; + return static_cast<const T2*>(Ty)->getBitWidth() == Bits; +} + +} +#endif // SPIRVTYPE_HPP_ diff --git a/lib/SPIRV/libSPIRV/SPIRVUtil.h b/lib/SPIRV/libSPIRV/SPIRVUtil.h index 0e7d875..b474ea9 100644 --- a/lib/SPIRV/libSPIRV/SPIRVUtil.h +++ b/lib/SPIRV/libSPIRV/SPIRVUtil.h @@ -1,64 +1,64 @@ -//===- SPIRVUtil.h - SPIR-V Utility Functions --------------------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines SPIR-V utility functions.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVUTIL_H_
-#define SPIRVUTIL_H_
-
-#ifdef _SPIRV_LLVM_API
-#include "llvm/Support/raw_ostream.h"
-#define spv_ostream llvm::raw_ostream
-#else
-#include <ostream>
-#define spv_ostream std::ostream
-#endif
-
-#include <algorithm>
-#include <cassert>
-#include <cstdint>
-#include <functional>
-#include <limits>
-#include <map>
-#include <set>
-#include <sstream>
-#include <string>
-#include <unordered_set>
-#include <vector>
+//===- SPIRVUtil.h - SPIR-V Utility Functions --------------------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines SPIR-V utility functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVUTIL_H_ +#define SPIRVUTIL_H_ + +#ifdef _SPIRV_LLVM_API +#include "llvm/Support/raw_ostream.h" +#define spv_ostream llvm::raw_ostream +#else +#include <ostream> +#define spv_ostream std::ostream +#endif + +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <functional> +#include <limits> +#include <map> +#include <set> +#include <sstream> +#include <string> +#include <unordered_set> +#include <vector> // MSVC supports "magic statics" since MSVS 2015. // For the previous version of MSVS we should guard @@ -67,380 +67,380 @@ #include "llvm/Support/Mutex.h" #include "llvm/Support/MutexGuard.h" #endif // LLVM_MSC_PREREQ(1900) -
-namespace SPIRV{
+ +namespace SPIRV{ #if defined (_MSC_VER) && (_MSC_VER < 1900) static llvm::sys::Mutex MapLock; #endif // LLVM_MSC_PREREQ(1900) -
-#define SPIRV_DEF_NAMEMAP(Type,MapType) \
-typedef SPIRVMap<Type, std::string> MapType; \
-inline MapType getNameMap(Type){ MapType MT; return MT;}
-
-// A bi-way map
-template<class Ty1, class Ty2, class Identifier = void>
-struct SPIRVMap {
-public:
- typedef Ty1 KeyTy;
- typedef Ty2 ValueTy;
- // Initialize map entries
- void init();
-
- static Ty2 map(Ty1 Key) {
- Ty2 Val;
- bool Found = find(Key, &Val);
+ +#define SPIRV_DEF_NAMEMAP(Type,MapType) \ +typedef SPIRVMap<Type, std::string> MapType; \ +inline MapType getNameMap(Type){ MapType MT; return MT;} + +// A bi-way map +template<class Ty1, class Ty2, class Identifier = void> +struct SPIRVMap { +public: + typedef Ty1 KeyTy; + typedef Ty2 ValueTy; + // Initialize map entries + void init(); + + static Ty2 map(Ty1 Key) { + Ty2 Val; + bool Found = find(Key, &Val); (void)Found; - assert (Found && "Invalid key");
- return Val;
- }
-
- static Ty1 rmap(Ty2 Key) {
- Ty1 Val;
- bool Found = rfind(Key, &Val);
+ assert (Found && "Invalid key"); + return Val; + } + + static Ty1 rmap(Ty2 Key) { + Ty1 Val; + bool Found = rfind(Key, &Val); (void)Found; - assert (Found && "Invalid key");
- return Val;
- }
-
- static const SPIRVMap& getMap() {
+ assert (Found && "Invalid key"); + return Val; + } + + static const SPIRVMap& getMap() { #if defined (_MSC_VER) && (_MSC_VER < 1900) llvm::sys::ScopedLock mapGuard(MapLock); #endif // LLVM_MSC_PREREQ(1900) - static const SPIRVMap Map(false);
- return Map;
- }
-
- static const SPIRVMap& getRMap() {
+ static const SPIRVMap Map(false); + return Map; + } + + static const SPIRVMap& getRMap() { #if defined (_MSC_VER) && (_MSC_VER < 1900) llvm::sys::ScopedLock mapGuard(MapLock); #endif // LLVM_MSC_PREREQ(1900) - static const SPIRVMap Map(true);
- return Map;
- }
-
- static void foreach(std::function<void(Ty1, Ty2)>F) {
- for (auto &I:getMap().Map)
- F(I.first, I.second);
- }
-
- // For each key/value in the map executes function \p F.
- // If \p F returns false break the iteration.
- static void foreach_conditional(std::function<bool(const Ty1&, Ty2)>F) {
- for (auto &I:getMap().Map) {
- if (!F(I.first, I.second))
- break;
- }
- }
-
- static bool find(Ty1 Key, Ty2 *Val = nullptr) {
- const SPIRVMap& Map = getMap();
- typename MapTy::const_iterator Loc = Map.Map.find(Key);
- if(Loc == Map.Map.end())
- return false;
- if (Val)
- *Val = Loc->second;
- return true;
- }
-
- static bool rfind(Ty2 Key, Ty1 *Val = nullptr) {
- const SPIRVMap& Map = getRMap();
- typename RevMapTy::const_iterator Loc = Map.RevMap.find(Key);
- if (Loc == Map.RevMap.end())
- return false;
- if (Val)
- *Val = Loc->second;
- return true;
- }
- SPIRVMap():IsReverse(false){}
-protected:
- SPIRVMap(bool Reverse):IsReverse(Reverse){
- init();
- }
- typedef std::map<Ty1, Ty2> MapTy;
- typedef std::map<Ty2, Ty1> RevMapTy;
-
- void add(Ty1 V1, Ty2 V2) {
- if (IsReverse) {
- RevMap[V2] = V1;
- return;
- }
- Map[V1] = V2;
- }
- MapTy Map;
- RevMapTy RevMap;
- bool IsReverse;
-};
-
-inline std::vector<std::string>
-getVec(const std::string &S, char Delim) {
- std::vector<std::string> Strs;
- std::stringstream SS(S);
- std::string Item;
- while (std::getline(SS, Item, Delim))
- Strs.push_back(Item);
- return Strs;
-}
-
-inline std::unordered_set<std::string>
-getUnordSet(const std::string &S, char Delim = ' ') {
- std::unordered_set<std::string> Strs;
- std::stringstream SS(S);
- std::string Item;
- while (std::getline(SS, Item, Delim))
- Strs.insert(Item);
- return Strs;
-}
-
-inline std::set<std::string>
-getSet(const std::string &S, char Delim = ' ') {
- std::set<std::string> Strs;
- std::stringstream SS(S);
- std::string Item;
- while (std::getline(SS, Item, Delim))
- Strs.insert(Item);
- return Strs;
-}
-
-template<typename VT, typename KT>
-VT map(KT Key) {
- return SPIRVMap<KT, VT>::map(Key);
-}
-
-template<typename KT, typename VT>
-KT rmap(VT V) {
- return SPIRVMap<KT, VT>::rmap(V);
-}
-
-template<typename VT, typename KT>
-std::unordered_set<VT>
-map(const std::unordered_set<KT> &KSet) {
- VT V;
- std::unordered_set<VT> VSet;
- for (auto &I:KSet)
- if (SPIRVMap<KT, VT>::find(I, &V))
- VSet.insert(V);
- return VSet;
-}
-
-template<typename VT, typename KT>
-std::set<VT>
-map(const std::set<KT> &KSet) {
- VT V;
- std::set<VT> VSet;
- for (auto &I:KSet)
- if (SPIRVMap<KT, VT>::find(I, &V))
- VSet.insert(V);
- return VSet;
-}
-
-template<typename KT, typename VT>
-std::unordered_set<KT>
-rmap(const std::unordered_set<VT> &KSet) {
- KT V;
- std::unordered_set<KT> VSet;
- for (auto &I:KSet)
- if (SPIRVMap<KT, VT>::rfind(I, &V))
- VSet.insert(V);
- return VSet;
-}
-
-template<typename KT, typename VT>
-std::set<KT>
-rmap(const std::set<VT> &KSet) {
- KT V;
- std::set<KT> VSet;
- for (auto &I:KSet)
- if (SPIRVMap<KT, VT>::rfind(I, &V))
- VSet.insert(V);
- return VSet;
-}
-
-template<typename KT, typename VT, typename Any>
-std::set<KT>
-rmap(const std::map<VT, Any>& KMap) {
- KT V;
- std::set<KT> VSet;
- for (auto &I : KMap)
- if (SPIRVMap<KT, VT>::rfind(I.first, &V))
- VSet.insert(V);
-
- return VSet;
-}
-
-template<typename K>
-std::string
-getName(K Key) {
- std::string Name;
- if (SPIRVMap<K, std::string>::find(Key, &Name))
- return Name;
- return "";
-}
-
-template<typename K>
-bool getByName(const std::string &Name, K &Key) {
- return SPIRVMap<K, std::string>::rfind(Name, &Key);
-}
-
-// Add a number as a string to a string
-template<class T>
-std::string
-concat(const std::string& s, const T& n) {
- std::stringstream ss;
- ss << s << n;
- return ss.str();
-}
-
-inline std::string
-concat(const std::string &S1, const std::string &S2, char Delim = ' ') {
- std::string S;
- if (S1.empty())
- S = S2;
- else if (!S2.empty())
- S = S1 + Delim + S2;
- return S;
-}
-
-inline std::string
-operator+(const std::string& s, int n) {
- return concat(s, n);
-}
-
-inline std::string
-operator+(const std::string& s, unsigned n) {
- return concat(s, n);
-}
-
-template<typename T>
-std::string
-getStr(const T &C, char Delim = ' ') {
- std::stringstream SS;
- bool First = true;
- for (auto &I:C) {
- if (!First)
- SS << Delim;
- else
- First = false;
- SS << I;
- }
- return SS.str();
-}
-
-template<class MapTy>
-unsigned mapBitMask(unsigned BM) {
- unsigned Res = 0;
- MapTy::foreach([&](typename MapTy::KeyTy K, typename MapTy::ValueTy V){
- Res |= BM & (unsigned)K ? (unsigned)V : 0;
- });
- return Res;
-}
-
-template<class MapTy>
-unsigned rmapBitMask(unsigned BM) {
- unsigned Res = 0;
- MapTy::foreach([&](typename MapTy::KeyTy K, typename MapTy::ValueTy V){
- Res |= BM & (unsigned)V ? (unsigned)K : 0;
- });
- return Res;
-}
-
-// Get the number of words used for encoding a string literal in SPIRV
-inline unsigned
-getSizeInWords(const std::string& Str) {
- assert(Str.length()/4 + 1 <= std::numeric_limits<unsigned>::max());
- return static_cast<unsigned>(Str.length()/4 + 1);
-}
-
-inline std::string
-getString(std::vector<uint32_t>::const_iterator Begin,
- std::vector<uint32_t>::const_iterator End) {
- std::string Str = std::string();
- for (auto I = Begin; I != End; ++I) {
- uint32_t Word = *I;
- for (unsigned J = 0u; J < 32u; J += 8u) {
- char Char = (char)((Word >> J) & 0xff);
- if (Char == '\0')
- return Str;
- Str += Char;
- }
- }
- return Str;
-}
-
-inline std::string
-getString(const std::vector<uint32_t> &V) {
- return getString(V.cbegin(), V.cend());
-}
-
-inline std::vector<uint32_t>
-getVec(const std::string &Str) {
- std::vector<uint32_t> V;
- auto StrSize = Str.size();
- uint32_t CurrentWord = 0u;
- for (unsigned I = 0u; I < StrSize; ++I) {
- if (I % 4u == 0u && I != 0u) {
- V.push_back(CurrentWord);
- CurrentWord = 0u;
- }
- assert(Str[I] && "0 is not allowed in string");
- CurrentWord += ((uint32_t)Str[I]) << ((I % 4u) * 8u);
- }
- if (CurrentWord != 0u)
- V.push_back(CurrentWord);
- if (StrSize % 4 == 0)
- V.push_back(0);
- return V;
-}
-
-template<typename T>
-inline std::vector<T>
-getVec(T Op1) {
- std::vector<T> V;
- V.push_back(Op1);
- return V;
-}
-
-template<typename T>
-inline std::vector<T>
-getVec(T Op1, T Op2) {
- std::vector<T> V;
- V.push_back(Op1);
- V.push_back(Op2);
- return V;
-}
-
-template<typename T>
-inline std::vector<T>
-getVec(T Op1, T Op2, T Op3) {
- std::vector<T> V;
- V.push_back(Op1);
- V.push_back(Op2);
- V.push_back(Op3);
- return V;
-}
-
-template<typename T>
-inline std::vector<T>
-getVec(T Op1, const std::vector<T> &Ops2) {
- std::vector<T> V;
- V.push_back(Op1);
- V.insert(V.end(), Ops2.begin(), Ops2.end());
- return V;
-}
-
-template<typename MapTy, typename FuncTy>
-typename MapTy::mapped_type
-getOrInsert(
- MapTy &Map,
- typename MapTy::key_type Key,
- FuncTy Func){
- typename MapTy::iterator Loc = Map.find(Key);
- if (Loc != Map.end())
- return Loc->second;
- typename MapTy::mapped_type NF = Func();
- Map[Key] = NF;
- return NF;
-}
-
-}
-
-#endif /* SPIRVUTIL_HPP_ */
+ static const SPIRVMap Map(true); + return Map; + } + + static void foreach(std::function<void(Ty1, Ty2)>F) { + for (auto &I:getMap().Map) + F(I.first, I.second); + } + + // For each key/value in the map executes function \p F. + // If \p F returns false break the iteration. + static void foreach_conditional(std::function<bool(const Ty1&, Ty2)>F) { + for (auto &I:getMap().Map) { + if (!F(I.first, I.second)) + break; + } + } + + static bool find(Ty1 Key, Ty2 *Val = nullptr) { + const SPIRVMap& Map = getMap(); + typename MapTy::const_iterator Loc = Map.Map.find(Key); + if(Loc == Map.Map.end()) + return false; + if (Val) + *Val = Loc->second; + return true; + } + + static bool rfind(Ty2 Key, Ty1 *Val = nullptr) { + const SPIRVMap& Map = getRMap(); + typename RevMapTy::const_iterator Loc = Map.RevMap.find(Key); + if (Loc == Map.RevMap.end()) + return false; + if (Val) + *Val = Loc->second; + return true; + } + SPIRVMap():IsReverse(false){} +protected: + SPIRVMap(bool Reverse):IsReverse(Reverse){ + init(); + } + typedef std::map<Ty1, Ty2> MapTy; + typedef std::map<Ty2, Ty1> RevMapTy; + + void add(Ty1 V1, Ty2 V2) { + if (IsReverse) { + RevMap[V2] = V1; + return; + } + Map[V1] = V2; + } + MapTy Map; + RevMapTy RevMap; + bool IsReverse; +}; + +inline std::vector<std::string> +getVec(const std::string &S, char Delim) { + std::vector<std::string> Strs; + std::stringstream SS(S); + std::string Item; + while (std::getline(SS, Item, Delim)) + Strs.push_back(Item); + return Strs; +} + +inline std::unordered_set<std::string> +getUnordSet(const std::string &S, char Delim = ' ') { + std::unordered_set<std::string> Strs; + std::stringstream SS(S); + std::string Item; + while (std::getline(SS, Item, Delim)) + Strs.insert(Item); + return Strs; +} + +inline std::set<std::string> +getSet(const std::string &S, char Delim = ' ') { + std::set<std::string> Strs; + std::stringstream SS(S); + std::string Item; + while (std::getline(SS, Item, Delim)) + Strs.insert(Item); + return Strs; +} + +template<typename VT, typename KT> +VT map(KT Key) { + return SPIRVMap<KT, VT>::map(Key); +} + +template<typename KT, typename VT> +KT rmap(VT V) { + return SPIRVMap<KT, VT>::rmap(V); +} + +template<typename VT, typename KT> +std::unordered_set<VT> +map(const std::unordered_set<KT> &KSet) { + VT V; + std::unordered_set<VT> VSet; + for (auto &I:KSet) + if (SPIRVMap<KT, VT>::find(I, &V)) + VSet.insert(V); + return VSet; +} + +template<typename VT, typename KT> +std::set<VT> +map(const std::set<KT> &KSet) { + VT V; + std::set<VT> VSet; + for (auto &I:KSet) + if (SPIRVMap<KT, VT>::find(I, &V)) + VSet.insert(V); + return VSet; +} + +template<typename KT, typename VT> +std::unordered_set<KT> +rmap(const std::unordered_set<VT> &KSet) { + KT V; + std::unordered_set<KT> VSet; + for (auto &I:KSet) + if (SPIRVMap<KT, VT>::rfind(I, &V)) + VSet.insert(V); + return VSet; +} + +template<typename KT, typename VT> +std::set<KT> +rmap(const std::set<VT> &KSet) { + KT V; + std::set<KT> VSet; + for (auto &I:KSet) + if (SPIRVMap<KT, VT>::rfind(I, &V)) + VSet.insert(V); + return VSet; +} + +template<typename KT, typename VT, typename Any> +std::set<KT> +rmap(const std::map<VT, Any>& KMap) { + KT V; + std::set<KT> VSet; + for (auto &I : KMap) + if (SPIRVMap<KT, VT>::rfind(I.first, &V)) + VSet.insert(V); + + return VSet; +} + +template<typename K> +std::string +getName(K Key) { + std::string Name; + if (SPIRVMap<K, std::string>::find(Key, &Name)) + return Name; + return ""; +} + +template<typename K> +bool getByName(const std::string &Name, K &Key) { + return SPIRVMap<K, std::string>::rfind(Name, &Key); +} + +// Add a number as a string to a string +template<class T> +std::string +concat(const std::string& s, const T& n) { + std::stringstream ss; + ss << s << n; + return ss.str(); +} + +inline std::string +concat(const std::string &S1, const std::string &S2, char Delim = ' ') { + std::string S; + if (S1.empty()) + S = S2; + else if (!S2.empty()) + S = S1 + Delim + S2; + return S; +} + +inline std::string +operator+(const std::string& s, int n) { + return concat(s, n); +} + +inline std::string +operator+(const std::string& s, unsigned n) { + return concat(s, n); +} + +template<typename T> +std::string +getStr(const T &C, char Delim = ' ') { + std::stringstream SS; + bool First = true; + for (auto &I:C) { + if (!First) + SS << Delim; + else + First = false; + SS << I; + } + return SS.str(); +} + +template<class MapTy> +unsigned mapBitMask(unsigned BM) { + unsigned Res = 0; + MapTy::foreach([&](typename MapTy::KeyTy K, typename MapTy::ValueTy V){ + Res |= BM & (unsigned)K ? (unsigned)V : 0; + }); + return Res; +} + +template<class MapTy> +unsigned rmapBitMask(unsigned BM) { + unsigned Res = 0; + MapTy::foreach([&](typename MapTy::KeyTy K, typename MapTy::ValueTy V){ + Res |= BM & (unsigned)V ? (unsigned)K : 0; + }); + return Res; +} + +// Get the number of words used for encoding a string literal in SPIRV +inline unsigned +getSizeInWords(const std::string& Str) { + assert(Str.length()/4 + 1 <= std::numeric_limits<unsigned>::max()); + return static_cast<unsigned>(Str.length()/4 + 1); +} + +inline std::string +getString(std::vector<uint32_t>::const_iterator Begin, + std::vector<uint32_t>::const_iterator End) { + std::string Str = std::string(); + for (auto I = Begin; I != End; ++I) { + uint32_t Word = *I; + for (unsigned J = 0u; J < 32u; J += 8u) { + char Char = (char)((Word >> J) & 0xff); + if (Char == '\0') + return Str; + Str += Char; + } + } + return Str; +} + +inline std::string +getString(const std::vector<uint32_t> &V) { + return getString(V.cbegin(), V.cend()); +} + +inline std::vector<uint32_t> +getVec(const std::string &Str) { + std::vector<uint32_t> V; + auto StrSize = Str.size(); + uint32_t CurrentWord = 0u; + for (unsigned I = 0u; I < StrSize; ++I) { + if (I % 4u == 0u && I != 0u) { + V.push_back(CurrentWord); + CurrentWord = 0u; + } + assert(Str[I] && "0 is not allowed in string"); + CurrentWord += ((uint32_t)Str[I]) << ((I % 4u) * 8u); + } + if (CurrentWord != 0u) + V.push_back(CurrentWord); + if (StrSize % 4 == 0) + V.push_back(0); + return V; +} + +template<typename T> +inline std::vector<T> +getVec(T Op1) { + std::vector<T> V; + V.push_back(Op1); + return V; +} + +template<typename T> +inline std::vector<T> +getVec(T Op1, T Op2) { + std::vector<T> V; + V.push_back(Op1); + V.push_back(Op2); + return V; +} + +template<typename T> +inline std::vector<T> +getVec(T Op1, T Op2, T Op3) { + std::vector<T> V; + V.push_back(Op1); + V.push_back(Op2); + V.push_back(Op3); + return V; +} + +template<typename T> +inline std::vector<T> +getVec(T Op1, const std::vector<T> &Ops2) { + std::vector<T> V; + V.push_back(Op1); + V.insert(V.end(), Ops2.begin(), Ops2.end()); + return V; +} + +template<typename MapTy, typename FuncTy> +typename MapTy::mapped_type +getOrInsert( + MapTy &Map, + typename MapTy::key_type Key, + FuncTy Func){ + typename MapTy::iterator Loc = Map.find(Key); + if (Loc != Map.end()) + return Loc->second; + typename MapTy::mapped_type NF = Func(); + Map[Key] = NF; + return NF; +} + +} + +#endif /* SPIRVUTIL_HPP_ */ diff --git a/lib/SPIRV/libSPIRV/SPIRVValue.cpp b/lib/SPIRV/libSPIRV/SPIRVValue.cpp index 1bd9674..18347ac 100644 --- a/lib/SPIRV/libSPIRV/SPIRVValue.cpp +++ b/lib/SPIRV/libSPIRV/SPIRVValue.cpp @@ -1,76 +1,76 @@ -//===- SPIRVValue.cpp – Class to represent a SPIR-V Value --------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines the values defined in SPIR-V spec with op codes.
-///
-/// The name of the SPIR-V values follow the op code name in the spec.
-/// This is for readability and ease of using macro to handle types.
-//
-//===----------------------------------------------------------------------===//
-
-#include "SPIRVValue.h"
-#include "SPIRVEnum.h"
-namespace SPIRV{
-void
-SPIRVValue::setAlignment(SPIRVWord A) {
- if (A == 0) {
- eraseDecorate(DecorationAlignment);
- return;
- }
- addDecorate(new SPIRVDecorate(DecorationAlignment, this, A));
- SPIRVDBG(spvdbgs() << "Set alignment " << A << " for obj " << Id << "\n")
-}
-
-bool
-SPIRVValue::hasAlignment(SPIRVWord *Result)const {
- return hasDecorate(DecorationAlignment, 0, Result);
-}
-
-bool
-SPIRVValue::isVolatile()const {
- return hasDecorate(DecorationVolatile);
-}
-
-void
-SPIRVValue::setVolatile(bool IsVolatile) {
- if (!IsVolatile) {
- eraseDecorate(DecorationVolatile);
- return;
- }
- addDecorate(new SPIRVDecorate(DecorationVolatile, this));
- SPIRVDBG(spvdbgs() << "Set volatile " << " for obj " << Id << "\n")
-}
-
-}
+//===- SPIRVValue.cpp – Class to represent a SPIR-V Value --------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines the values defined in SPIR-V spec with op codes. +/// +/// The name of the SPIR-V values follow the op code name in the spec. +/// This is for readability and ease of using macro to handle types. +// +//===----------------------------------------------------------------------===// + +#include "SPIRVValue.h" +#include "SPIRVEnum.h" +namespace SPIRV{ +void +SPIRVValue::setAlignment(SPIRVWord A) { + if (A == 0) { + eraseDecorate(DecorationAlignment); + return; + } + addDecorate(new SPIRVDecorate(DecorationAlignment, this, A)); + SPIRVDBG(spvdbgs() << "Set alignment " << A << " for obj " << Id << "\n") +} + +bool +SPIRVValue::hasAlignment(SPIRVWord *Result)const { + return hasDecorate(DecorationAlignment, 0, Result); +} + +bool +SPIRVValue::isVolatile()const { + return hasDecorate(DecorationVolatile); +} + +void +SPIRVValue::setVolatile(bool IsVolatile) { + if (!IsVolatile) { + eraseDecorate(DecorationVolatile); + return; + } + addDecorate(new SPIRVDecorate(DecorationVolatile, this)); + SPIRVDBG(spvdbgs() << "Set volatile " << " for obj " << Id << "\n") +} + +} diff --git a/lib/SPIRV/libSPIRV/SPIRVValue.h b/lib/SPIRV/libSPIRV/SPIRVValue.h index 812a635..419aed7 100644 --- a/lib/SPIRV/libSPIRV/SPIRVValue.h +++ b/lib/SPIRV/libSPIRV/SPIRVValue.h @@ -1,407 +1,407 @@ -//===- SPIRVValue.h - Class to represent a SPIR-V Value ----------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines the values defined in SPIR-V spec with op codes.
-///
-/// The name of the SPIR-V values follow the op code name in the spec.
-/// This is for readability and ease of using macro to handle types.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SPIRVVALUE_HPP_
-#define SPIRVVALUE_HPP_
-
-#include "SPIRVEntry.h"
-#include "SPIRVType.h"
-#include "SPIRVDecorate.h"
-
-#include <iostream>
-#include <map>
-#include <memory>
-
-namespace SPIRV{
-
-class SPIRVValue: public SPIRVEntry {
-public:
- // Complete constructor for value with id and type
- SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
- SPIRVType *TheType, SPIRVId TheId)
- :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(TheType) {
- validate();
- }
- // Complete constructor for value with type but without id
- SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
- SPIRVType *TheType)
- :SPIRVEntry(M, TheWordCount, TheOpCode), Type(TheType) {
- setHasNoId();
- validate();
- }
- // Complete constructor for value with id but without type
- SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode,
- SPIRVId TheId)
- :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(NULL) {
- setHasNoType();
- validate();
- }
- // Complete constructor for value without id and type
- SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode)
- :SPIRVEntry(M, TheWordCount, TheOpCode), Type(NULL) {
- setHasNoId();
- setHasNoType();
- validate();
- }
- // Incomplete constructor
- SPIRVValue(Op TheOpCode):SPIRVEntry(TheOpCode), Type(NULL) {}
-
- bool hasType()const { return !(Attrib & SPIRVEA_NOTYPE);}
- SPIRVType *getType()const {
- assert(hasType() && "value has no type");
- return Type;
- }
- bool isVolatile()const;
- bool hasAlignment(SPIRVWord *Result=0)const;
-
- void setAlignment(SPIRVWord);
- void setVolatile(bool IsVolatile);
-
- void validate()const {
- SPIRVEntry::validate();
- assert((!hasType() || Type) && "Invalid type");
- }
-
- void setType(SPIRVType *Ty) {
- Type = Ty;
- assert(!Ty || !Ty->isTypeVoid() || OpCode == OpFunction);
- if (Ty && (!Ty->isTypeVoid() || OpCode == OpFunction))
- setHasType();
- else
- setHasNoType();
- }
-
- SPIRVCapVec getRequiredCapability() const {
- SPIRVCapVec CV;
- if (!hasType())
- return std::move(CV);
- return std::move(Type->getRequiredCapability());
- }
-
-protected:
- void setHasNoType() { Attrib |= SPIRVEA_NOTYPE;}
- void setHasType() { Attrib &= ~SPIRVEA_NOTYPE;}
-
- SPIRVType *Type; // Value Type
-};
-
-class SPIRVConstant: public SPIRVValue {
-public:
- // Complete constructor for integer constant
- SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
- uint64_t TheValue)
- :SPIRVValue(M, 0, OpConstant, TheType, TheId){
- Union.UInt64Val = TheValue;
- recalculateWordCount();
- validate();
- }
- // Complete constructor for float constant
- SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, float TheValue)
- :SPIRVValue(M, 0, OpConstant, TheType, TheId){
- Union.FloatVal = TheValue;
- recalculateWordCount();
- validate();
- }
- // Complete constructor for double constant
- SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, double TheValue)
- :SPIRVValue(M, 0, OpConstant, TheType, TheId){
- Union.DoubleVal = TheValue;
- recalculateWordCount();
- validate();
- }
- // Incomplete constructor
- SPIRVConstant():SPIRVValue(OpConstant), NumWords(0){}
- uint64_t getZExtIntValue() const { return Union.UInt64Val;}
- float getFloatValue() const { return Union.FloatVal;}
- double getDoubleValue() const { return Union.DoubleVal;}
-protected:
- void recalculateWordCount() {
- NumWords = Type->getBitWidth()/32;
- if (NumWords < 1)
- NumWords = 1;
- WordCount = 3 + NumWords;
- }
- void validate() const {
- SPIRVValue::validate();
- assert(NumWords >= 1 && NumWords <= 2 && "Invalid constant size");
- }
- void encode(spv_ostream &O) const {
- getEncoder(O) << Type << Id;
- for (unsigned i = 0; i < NumWords; ++i)
- getEncoder(O) << Union.Words[i];
- }
- void setWordCount(SPIRVWord WordCount) {
- SPIRVValue::setWordCount(WordCount);
- NumWords = WordCount - 3;
- }
- void decode(std::istream &I) {
- getDecoder(I) >> Type >> Id;
- for (unsigned i = 0; i < NumWords; ++i)
- getDecoder(I) >> Union.Words[i];
- }
-
- unsigned NumWords;
- union UnionType{
- uint64_t UInt64Val;
- float FloatVal;
- double DoubleVal;
- SPIRVWord Words[2];
- UnionType() {
- UInt64Val = 0;
- }
- } Union;
-};
-
-template<Op OC>
-class SPIRVConstantEmpty: public SPIRVValue {
-public:
- // Complete constructor
- SPIRVConstantEmpty(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
- :SPIRVValue(M, 3, OC, TheType, TheId){
- validate();
- }
- // Incomplete constructor
- SPIRVConstantEmpty():SPIRVValue(OC){}
-protected:
- void validate() const {
- SPIRVValue::validate();
- }
- _SPIRV_DEF_ENCDEC2(Type, Id)
-};
-
-template<Op OC>
-class SPIRVConstantBool: public SPIRVConstantEmpty<OC> {
-public:
- // Complete constructor
- SPIRVConstantBool(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
- :SPIRVConstantEmpty<OC>(M, TheType, TheId){}
- // Incomplete constructor
- SPIRVConstantBool(){}
-protected:
- void validate() const {
- SPIRVConstantEmpty<OC>::validate();
- assert(this->Type->isTypeBool() && "Invalid type");
- }
-};
-
-typedef SPIRVConstantBool<OpConstantTrue> SPIRVConstantTrue;
-typedef SPIRVConstantBool<OpConstantFalse> SPIRVConstantFalse;
-
-class SPIRVConstantNull:
- public SPIRVConstantEmpty<OpConstantNull> {
-public:
- // Complete constructor
- SPIRVConstantNull(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
- :SPIRVConstantEmpty(M, TheType, TheId){
- validate();
- }
- // Incomplete constructor
- SPIRVConstantNull(){}
-protected:
- void validate() const {
- SPIRVConstantEmpty::validate();
- assert((Type->isTypeComposite() ||
- Type->isTypeOpaque() ||
- Type->isTypeEvent() ||
- Type->isTypePointer() ||
- Type->isTypeReserveId() ||
- Type->isTypeDeviceEvent()) &&
- "Invalid type");
- }
-};
-
-class SPIRVUndef:
- public SPIRVConstantEmpty<OpUndef> {
-public:
- // Complete constructor
- SPIRVUndef(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId)
- :SPIRVConstantEmpty(M, TheType, TheId){
- validate();
- }
- // Incomplete constructor
- SPIRVUndef(){}
-protected:
- void validate() const {
- SPIRVConstantEmpty::validate();
- }
-};
-
-class SPIRVConstantComposite: public SPIRVValue {
-public:
- // Complete constructor for composite constant
- SPIRVConstantComposite(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
- const std::vector<SPIRVValue *> TheElements)
- :SPIRVValue(M, TheElements.size()+3, OpConstantComposite, TheType,
- TheId){
- Elements = getIds(TheElements);
- validate();
- }
- // Incomplete constructor
- SPIRVConstantComposite():SPIRVValue(OpConstantComposite){}
- std::vector<SPIRVValue*> getElements()const {
- return getValues(Elements);
- }
- std::vector<SPIRVEntry*> getNonLiteralOperands() const {
- std::vector<SPIRVValue*> Elements = getElements();
- return std::vector<SPIRVEntry*>(Elements.begin(), Elements.end());
- }
-protected:
- void validate() const {
- SPIRVValue::validate();
- for (auto &I:Elements)
- getValue(I)->validate();
- }
- void setWordCount(SPIRVWord WordCount) {
- SPIRVEntry::setWordCount(WordCount);
- Elements.resize(WordCount - 3);
- }
- _SPIRV_DEF_ENCDEC3(Type, Id, Elements)
-
- std::vector<SPIRVId> Elements;
-};
-
-class SPIRVConstantSampler: public SPIRVValue {
-public:
- const static Op OC = OpConstantSampler;
- const static SPIRVWord WC = 6;
- // Complete constructor
- SPIRVConstantSampler(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
- SPIRVWord TheAddrMode, SPIRVWord TheNormalized, SPIRVWord TheFilterMode)
- :SPIRVValue(M, WC, OC, TheType, TheId), AddrMode(TheAddrMode),
- Normalized(TheNormalized), FilterMode(TheFilterMode){
- validate();
- }
- // Incomplete constructor
- SPIRVConstantSampler():SPIRVValue(OC), AddrMode(SPIRVSAM_Invalid),
- Normalized(SPIRVWORD_MAX), FilterMode(SPIRVSFM_Invalid){}
-
- SPIRVWord getAddrMode() const {
- return AddrMode;
- }
-
- SPIRVWord getFilterMode() const {
- return FilterMode;
- }
-
- SPIRVWord getNormalized() const {
- return Normalized;
- }
- SPIRVCapVec getRequiredCapability() const {
- return getVec(CapabilityLiteralSampler);
- }
-protected:
- SPIRVWord AddrMode;
- SPIRVWord Normalized;
- SPIRVWord FilterMode;
- void validate() const {
- SPIRVValue::validate();
- assert(OpCode == OC);
- assert(WordCount == WC);
- assert(Type->isTypeSampler());
- }
- _SPIRV_DEF_ENCDEC5(Type, Id, AddrMode, Normalized, FilterMode)
-};
-
-class SPIRVConstantPipeStorage : public SPIRVValue {
-public:
- const static Op OC = OpConstantPipeStorage;
- const static SPIRVWord WC = 6;
- // Complete constructor
- SPIRVConstantPipeStorage(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId,
- SPIRVWord ThePacketSize, SPIRVWord ThePacketAlign, SPIRVWord TheCapacity)
- :SPIRVValue(M, WC, OC, TheType, TheId), PacketSize(ThePacketSize),
- PacketAlign(ThePacketAlign), Capacity(TheCapacity){
- validate();
- }
- // Incomplete constructor
- SPIRVConstantPipeStorage() :SPIRVValue(OC), PacketSize(0),
- PacketAlign(0), Capacity(0){}
-
- SPIRVWord getPacketSize() const {
- return PacketSize;
- }
-
- SPIRVWord getPacketAlign() const {
- return PacketAlign;
- }
-
- SPIRVWord getCapacity() const {
- return Capacity;
- }
- SPIRVCapVec getRequiredCapability() const {
- return getVec(CapabilityPipes, CapabilityPipeStorage);
- }
-protected:
- SPIRVWord PacketSize;
- SPIRVWord PacketAlign;
- SPIRVWord Capacity;
- void validate() const {
- SPIRVValue::validate();
- assert(OpCode == OC);
- assert(WordCount == WC);
- assert(Type->isTypePipeStorage());
- }
- _SPIRV_DEF_ENCDEC5(Type, Id, PacketSize, PacketAlign, Capacity)
-};
-
-class SPIRVForward:public SPIRVValue, public SPIRVComponentExecutionModes {
-public:
- const static Op OC = OpForward;
- // Complete constructor
- SPIRVForward(SPIRVModule *TheModule, SPIRVType *TheTy, SPIRVId TheId):
- SPIRVValue(TheModule, 0, OC, TheId){
- if (TheTy)
- setType(TheTy);
- }
- SPIRVForward():SPIRVValue(OC) {
- assert(0 && "should never be called");
- }
- _SPIRV_DEF_ENCDEC1(Id)
- friend class SPIRVFunction;
-protected:
- void validate() const {}
-};
-
-}
-
-
-#endif /* SPIRVVALUE_HPP_ */
+//===- SPIRVValue.h - Class to represent a SPIR-V Value ----------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines the values defined in SPIR-V spec with op codes. +/// +/// The name of the SPIR-V values follow the op code name in the spec. +/// This is for readability and ease of using macro to handle types. +// +//===----------------------------------------------------------------------===// + +#ifndef SPIRVVALUE_HPP_ +#define SPIRVVALUE_HPP_ + +#include "SPIRVEntry.h" +#include "SPIRVType.h" +#include "SPIRVDecorate.h" + +#include <iostream> +#include <map> +#include <memory> + +namespace SPIRV{ + +class SPIRVValue: public SPIRVEntry { +public: + // Complete constructor for value with id and type + SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, + SPIRVType *TheType, SPIRVId TheId) + :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(TheType) { + validate(); + } + // Complete constructor for value with type but without id + SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, + SPIRVType *TheType) + :SPIRVEntry(M, TheWordCount, TheOpCode), Type(TheType) { + setHasNoId(); + validate(); + } + // Complete constructor for value with id but without type + SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode, + SPIRVId TheId) + :SPIRVEntry(M, TheWordCount, TheOpCode, TheId), Type(NULL) { + setHasNoType(); + validate(); + } + // Complete constructor for value without id and type + SPIRVValue(SPIRVModule *M, unsigned TheWordCount, Op TheOpCode) + :SPIRVEntry(M, TheWordCount, TheOpCode), Type(NULL) { + setHasNoId(); + setHasNoType(); + validate(); + } + // Incomplete constructor + SPIRVValue(Op TheOpCode):SPIRVEntry(TheOpCode), Type(NULL) {} + + bool hasType()const { return !(Attrib & SPIRVEA_NOTYPE);} + SPIRVType *getType()const { + assert(hasType() && "value has no type"); + return Type; + } + bool isVolatile()const; + bool hasAlignment(SPIRVWord *Result=0)const; + + void setAlignment(SPIRVWord); + void setVolatile(bool IsVolatile); + + void validate()const { + SPIRVEntry::validate(); + assert((!hasType() || Type) && "Invalid type"); + } + + void setType(SPIRVType *Ty) { + Type = Ty; + assert(!Ty || !Ty->isTypeVoid() || OpCode == OpFunction); + if (Ty && (!Ty->isTypeVoid() || OpCode == OpFunction)) + setHasType(); + else + setHasNoType(); + } + + SPIRVCapVec getRequiredCapability() const { + SPIRVCapVec CV; + if (!hasType()) + return std::move(CV); + return std::move(Type->getRequiredCapability()); + } + +protected: + void setHasNoType() { Attrib |= SPIRVEA_NOTYPE;} + void setHasType() { Attrib &= ~SPIRVEA_NOTYPE;} + + SPIRVType *Type; // Value Type +}; + +class SPIRVConstant: public SPIRVValue { +public: + // Complete constructor for integer constant + SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, + uint64_t TheValue) + :SPIRVValue(M, 0, OpConstant, TheType, TheId){ + Union.UInt64Val = TheValue; + recalculateWordCount(); + validate(); + } + // Complete constructor for float constant + SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, float TheValue) + :SPIRVValue(M, 0, OpConstant, TheType, TheId){ + Union.FloatVal = TheValue; + recalculateWordCount(); + validate(); + } + // Complete constructor for double constant + SPIRVConstant(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, double TheValue) + :SPIRVValue(M, 0, OpConstant, TheType, TheId){ + Union.DoubleVal = TheValue; + recalculateWordCount(); + validate(); + } + // Incomplete constructor + SPIRVConstant():SPIRVValue(OpConstant), NumWords(0){} + uint64_t getZExtIntValue() const { return Union.UInt64Val;} + float getFloatValue() const { return Union.FloatVal;} + double getDoubleValue() const { return Union.DoubleVal;} +protected: + void recalculateWordCount() { + NumWords = Type->getBitWidth()/32; + if (NumWords < 1) + NumWords = 1; + WordCount = 3 + NumWords; + } + void validate() const { + SPIRVValue::validate(); + assert(NumWords >= 1 && NumWords <= 2 && "Invalid constant size"); + } + void encode(spv_ostream &O) const { + getEncoder(O) << Type << Id; + for (unsigned i = 0; i < NumWords; ++i) + getEncoder(O) << Union.Words[i]; + } + void setWordCount(SPIRVWord WordCount) { + SPIRVValue::setWordCount(WordCount); + NumWords = WordCount - 3; + } + void decode(std::istream &I) { + getDecoder(I) >> Type >> Id; + for (unsigned i = 0; i < NumWords; ++i) + getDecoder(I) >> Union.Words[i]; + } + + unsigned NumWords; + union UnionType{ + uint64_t UInt64Val; + float FloatVal; + double DoubleVal; + SPIRVWord Words[2]; + UnionType() { + UInt64Val = 0; + } + } Union; +}; + +template<Op OC> +class SPIRVConstantEmpty: public SPIRVValue { +public: + // Complete constructor + SPIRVConstantEmpty(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) + :SPIRVValue(M, 3, OC, TheType, TheId){ + validate(); + } + // Incomplete constructor + SPIRVConstantEmpty():SPIRVValue(OC){} +protected: + void validate() const { + SPIRVValue::validate(); + } + _SPIRV_DEF_ENCDEC2(Type, Id) +}; + +template<Op OC> +class SPIRVConstantBool: public SPIRVConstantEmpty<OC> { +public: + // Complete constructor + SPIRVConstantBool(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) + :SPIRVConstantEmpty<OC>(M, TheType, TheId){} + // Incomplete constructor + SPIRVConstantBool(){} +protected: + void validate() const { + SPIRVConstantEmpty<OC>::validate(); + assert(this->Type->isTypeBool() && "Invalid type"); + } +}; + +typedef SPIRVConstantBool<OpConstantTrue> SPIRVConstantTrue; +typedef SPIRVConstantBool<OpConstantFalse> SPIRVConstantFalse; + +class SPIRVConstantNull: + public SPIRVConstantEmpty<OpConstantNull> { +public: + // Complete constructor + SPIRVConstantNull(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) + :SPIRVConstantEmpty(M, TheType, TheId){ + validate(); + } + // Incomplete constructor + SPIRVConstantNull(){} +protected: + void validate() const { + SPIRVConstantEmpty::validate(); + assert((Type->isTypeComposite() || + Type->isTypeOpaque() || + Type->isTypeEvent() || + Type->isTypePointer() || + Type->isTypeReserveId() || + Type->isTypeDeviceEvent()) && + "Invalid type"); + } +}; + +class SPIRVUndef: + public SPIRVConstantEmpty<OpUndef> { +public: + // Complete constructor + SPIRVUndef(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId) + :SPIRVConstantEmpty(M, TheType, TheId){ + validate(); + } + // Incomplete constructor + SPIRVUndef(){} +protected: + void validate() const { + SPIRVConstantEmpty::validate(); + } +}; + +class SPIRVConstantComposite: public SPIRVValue { +public: + // Complete constructor for composite constant + SPIRVConstantComposite(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, + const std::vector<SPIRVValue *> TheElements) + :SPIRVValue(M, TheElements.size()+3, OpConstantComposite, TheType, + TheId){ + Elements = getIds(TheElements); + validate(); + } + // Incomplete constructor + SPIRVConstantComposite():SPIRVValue(OpConstantComposite){} + std::vector<SPIRVValue*> getElements()const { + return getValues(Elements); + } + std::vector<SPIRVEntry*> getNonLiteralOperands() const { + std::vector<SPIRVValue*> Elements = getElements(); + return std::vector<SPIRVEntry*>(Elements.begin(), Elements.end()); + } +protected: + void validate() const { + SPIRVValue::validate(); + for (auto &I:Elements) + getValue(I)->validate(); + } + void setWordCount(SPIRVWord WordCount) { + SPIRVEntry::setWordCount(WordCount); + Elements.resize(WordCount - 3); + } + _SPIRV_DEF_ENCDEC3(Type, Id, Elements) + + std::vector<SPIRVId> Elements; +}; + +class SPIRVConstantSampler: public SPIRVValue { +public: + const static Op OC = OpConstantSampler; + const static SPIRVWord WC = 6; + // Complete constructor + SPIRVConstantSampler(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, + SPIRVWord TheAddrMode, SPIRVWord TheNormalized, SPIRVWord TheFilterMode) + :SPIRVValue(M, WC, OC, TheType, TheId), AddrMode(TheAddrMode), + Normalized(TheNormalized), FilterMode(TheFilterMode){ + validate(); + } + // Incomplete constructor + SPIRVConstantSampler():SPIRVValue(OC), AddrMode(SPIRVSAM_Invalid), + Normalized(SPIRVWORD_MAX), FilterMode(SPIRVSFM_Invalid){} + + SPIRVWord getAddrMode() const { + return AddrMode; + } + + SPIRVWord getFilterMode() const { + return FilterMode; + } + + SPIRVWord getNormalized() const { + return Normalized; + } + SPIRVCapVec getRequiredCapability() const { + return getVec(CapabilityLiteralSampler); + } +protected: + SPIRVWord AddrMode; + SPIRVWord Normalized; + SPIRVWord FilterMode; + void validate() const { + SPIRVValue::validate(); + assert(OpCode == OC); + assert(WordCount == WC); + assert(Type->isTypeSampler()); + } + _SPIRV_DEF_ENCDEC5(Type, Id, AddrMode, Normalized, FilterMode) +}; + +class SPIRVConstantPipeStorage : public SPIRVValue { +public: + const static Op OC = OpConstantPipeStorage; + const static SPIRVWord WC = 6; + // Complete constructor + SPIRVConstantPipeStorage(SPIRVModule *M, SPIRVType *TheType, SPIRVId TheId, + SPIRVWord ThePacketSize, SPIRVWord ThePacketAlign, SPIRVWord TheCapacity) + :SPIRVValue(M, WC, OC, TheType, TheId), PacketSize(ThePacketSize), + PacketAlign(ThePacketAlign), Capacity(TheCapacity){ + validate(); + } + // Incomplete constructor + SPIRVConstantPipeStorage() :SPIRVValue(OC), PacketSize(0), + PacketAlign(0), Capacity(0){} + + SPIRVWord getPacketSize() const { + return PacketSize; + } + + SPIRVWord getPacketAlign() const { + return PacketAlign; + } + + SPIRVWord getCapacity() const { + return Capacity; + } + SPIRVCapVec getRequiredCapability() const { + return getVec(CapabilityPipes, CapabilityPipeStorage); + } +protected: + SPIRVWord PacketSize; + SPIRVWord PacketAlign; + SPIRVWord Capacity; + void validate() const { + SPIRVValue::validate(); + assert(OpCode == OC); + assert(WordCount == WC); + assert(Type->isTypePipeStorage()); + } + _SPIRV_DEF_ENCDEC5(Type, Id, PacketSize, PacketAlign, Capacity) +}; + +class SPIRVForward:public SPIRVValue, public SPIRVComponentExecutionModes { +public: + const static Op OC = OpForward; + // Complete constructor + SPIRVForward(SPIRVModule *TheModule, SPIRVType *TheTy, SPIRVId TheId): + SPIRVValue(TheModule, 0, OC, TheId){ + if (TheTy) + setType(TheTy); + } + SPIRVForward():SPIRVValue(OC) { + assert(0 && "should never be called"); + } + _SPIRV_DEF_ENCDEC1(Id) + friend class SPIRVFunction; +protected: + void validate() const {} +}; + +} + + +#endif /* SPIRVVALUE_HPP_ */ diff --git a/lib/SPIRV/libSPIRV/libSPIRV.h b/lib/SPIRV/libSPIRV/libSPIRV.h index 74434d9..a51d843 100644 --- a/lib/SPIRV/libSPIRV/libSPIRV.h +++ b/lib/SPIRV/libSPIRV/libSPIRV.h @@ -1,52 +1,52 @@ -//===- libSPIRV.h – SPIR-V Header files -------------------------*- 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file includes all SPIRV header files.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LIBSPIRV_H_
-#define LIBSPIRV_H_
-
-#include "SPIRVOpCode.h"
-#include "SPIRVEntry.h"
-#include "SPIRVType.h"
-#include "SPIRVValue.h"
-#include "SPIRVModule.h"
-#include "SPIRVFunction.h"
-#include "SPIRVBasicBlock.h"
-#include "SPIRVInstruction.h"
-
-#endif
+//===- libSPIRV.h – SPIR-V Header files -------------------------*- 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file includes all SPIRV header files. +/// +//===----------------------------------------------------------------------===// + +#ifndef LIBSPIRV_H_ +#define LIBSPIRV_H_ + +#include "SPIRVOpCode.h" +#include "SPIRVEntry.h" +#include "SPIRVType.h" +#include "SPIRVValue.h" +#include "SPIRVModule.h" +#include "SPIRVFunction.h" +#include "SPIRVBasicBlock.h" +#include "SPIRVInstruction.h" + +#endif diff --git a/test/CheckCapKernelWithoutKernel.ll b/test/CheckCapKernelWithoutKernel.ll index 5cf9ba9..6fb6d74 100644 --- a/test/CheckCapKernelWithoutKernel.ll +++ b/test/CheckCapKernelWithoutKernel.ll @@ -1,24 +1,24 @@ -; RUN: llvm-as < %s | llvm-spirv -spirv-text -o %t
-; RUN: FileCheck < %t %s
-
-
-; ModuleID = '../rel/CheckCapKernelWithoutKernel.bc'
-target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
-target triple = "spir64-unknown-unknown"
-
-@a = addrspace(2) constant i32 1, align 4
-
-; CHECK-DAG: {{[0-9]*}} Capability Kernel
-
-!opencl.enable.FP_CONTRACT = !{}
-!opencl.spir.version = !{!0}
-!opencl.ocl.version = !{!1}
-!opencl.used.extensions = !{!2}
-!opencl.used.optional.core.features = !{!2}
-!opencl.compiler.options = !{!2}
-!llvm.ident = !{!3}
-
-!0 = !{i32 1, i32 2}
-!1 = !{i32 1, i32 0}
-!2 = !{}
+; RUN: llvm-as < %s | llvm-spirv -spirv-text -o %t +; RUN: FileCheck < %t %s + + +; ModuleID = '../rel/CheckCapKernelWithoutKernel.bc' +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64" +target triple = "spir64-unknown-unknown" + +@a = addrspace(2) constant i32 1, align 4 + +; CHECK-DAG: {{[0-9]*}} Capability Kernel + +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!0} +!opencl.ocl.version = !{!1} +!opencl.used.extensions = !{!2} +!opencl.used.optional.core.features = !{!2} +!opencl.compiler.options = !{!2} +!llvm.ident = !{!3} + +!0 = !{i32 1, i32 2} +!1 = !{i32 1, i32 0} +!2 = !{} !3 = !{!"clang version 3.6.1 "}
\ No newline at end of file diff --git a/test/CreatePipeFromPipeStorage.ll b/test/CreatePipeFromPipeStorage.ll index af280e8..671698f 100644 --- a/test/CreatePipeFromPipeStorage.ll +++ b/test/CreatePipeFromPipeStorage.ll @@ -1,169 +1,169 @@ -; RUN: llvm-as %s -o %t.bc
-; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt
-; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV
-; RUN: llvm-spirv %t.bc -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
-; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-
-; CHECK-LLVM: %"[[CL_PIPE_STORAGE_NAME:[^"]+]]" = type { %spirv.PipeStorage addrspace(1)* }
-; CHECK-LLVM: %"[[CL_READ_PIPE_NAME:[^"]+read>]]" = type { %spirv.Pipe._0 addrspace(1)* }
-; CHECK-LLVM: %spirv.Pipe._0 = type opaque
-; CHECK-LLVM: %"[[CL_WRITE_PIPE_NAME:[^"]+write>]]" = type { %spirv.Pipe._1 addrspace(1)* }
-; CHECK-LLVM: %spirv.Pipe._1 = type opaque
-
-
-; CHECK-SPIRV: Capability Pipes
-; CHECK-SPIRV: Capability PipeStorage
-
-; CHECK-SPIRV: Name [[PIPE_STORAGE_ID:[0-9]+]] "mygpipe"
-; CHECK-SPIRV: Name [[READ_PIPE_WRAPPER_ID:[0-9]+]] "myrpipe"
-; CHECK-SPIRV: Name [[WRITE_PIPE_WRAPPER_ID:[0-9]+]] "mywpipe"
-; CHECK-SPIRV: Name [[WRITE_PIPE_WRAPPER_CTOR:[0-9]+]] "_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE1EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE1EEE"
-; CHECK-SPIRV: Name [[READ_PIPE_WRAPPER_CTOR:[0-9]+]] "_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE0EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE0EEE"
-
-; CHECK-SPIRV: TypeInt [[INT_T:[0-9]+]] 32 0
-; CHECK-SPIRV: Constant [[INT_T]] [[CONSTANT_ZERO_ID:[0-9]+]] 0
-
-; CHECK-SPIRV: TypePipe [[READ_PIPE:[0-9]+]] 0
-; CHECK-SPIRV: TypeStruct [[READ_PIPE_WRAPPER:[0-9]+]] [[READ_PIPE]]
-; CHECK-SPIRV: TypePointer [[READ_PIPE_WRAPPER_PTR:[0-9]+]] 7 [[READ_PIPE_WRAPPER]]
-; CHECK-SPIRV: TypePipe [[WRITE_PIPE:[0-9]+]] 1
-; CHECK-SPIRV: TypeStruct [[WRITE_PIPE_WRAPPER:[0-9]+]] [[WRITE_PIPE]]
-
-; CHECK-SPIRV: TypePointer [[WRITE_PIPE_WRAPPER_PTR:[0-9]+]] 7 [[WRITE_PIPE_WRAPPER]]
-
-
-target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir-unknown-unknown"
-
-%spirv.ConstantPipeStorage = type { i32, i32, i32 }
-%"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" = type { %spirv.PipeStorage addrspace(1)* }
-%spirv.PipeStorage = type opaque
-%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" = type { %spirv.Pipe._0 addrspace(1)* }
-%spirv.Pipe._0 = type opaque
-%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" = type { %spirv.Pipe._1 addrspace(1)* }
-%spirv.Pipe._1 = type opaque
-
-@_ZN2cl9__details29OpConstantPipeStorage_CreatorILi16ELi16ELi1EE5valueE = linkonce_odr addrspace(1) global %spirv.ConstantPipeStorage { i32 16, i32 16, i32 1 }, align 4
-@mygpipe = addrspace(1) global %"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" { %spirv.PipeStorage addrspace(1)* bitcast (%spirv.ConstantPipeStorage addrspace(1)* @_ZN2cl9__details29OpConstantPipeStorage_CreatorILi16ELi16ELi1EE5valueE to %spirv.PipeStorage addrspace(1)*) }, align 4
-
-
-; Function Attrs: nounwind
-define spir_kernel void @worker() {
-entry:
- ; CHECK-LLVM: %myrpipe = alloca %"[[CL_READ_PIPE_NAME]]", align 4
- ; CHECK-LLVM: %mywpipe = alloca %"[[CL_WRITE_PIPE_NAME]]", align 4
-
- ; CHECK-SPIRV: Variable [[READ_PIPE_WRAPPER_PTR]] [[READ_PIPE_WRAPPER_ID]] 7
- ; CHECK-SPIRV: Variable [[WRITE_PIPE_WRAPPER_PTR]] [[WRITE_PIPE_WRAPPER_ID]] 7
-
- %myrpipe = alloca %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>", align 4
- %mywpipe = alloca %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>", align 4
-
-
- ; CHECK-LLVM: %[[ID0:[0-9]+]] = addrspacecast %"[[CL_PIPE_STORAGE_NAME]]" addrspace(1)* @mygpipe to %"[[CL_PIPE_STORAGE_NAME]]" addrspace(4)*
- ; CHECK-LLVM: %[[ID1:[0-9]+]] = getelementptr %"[[CL_PIPE_STORAGE_NAME]]", %"[[CL_PIPE_STORAGE_NAME]]" addrspace(4)* %[[ID0]], i32 0, i32 0
-
- ; CHECK-SPIRV: PtrCastToGeneric {{[0-9]+}} [[SPIRV0:[0-9]+]] [[PIPE_STORAGE_ID]]
- ; CHECK-SPIRV: PtrAccessChain {{[0-9]+}} [[SPIRV1:[0-9]+]] [[SPIRV0]] [[CONSTANT_ZERO_ID]] [[CONSTANT_ZERO_ID]]
-
- %0 = addrspacecast %"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" addrspace(1)* @mygpipe to %"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" addrspace(4)*
- %1 = getelementptr %"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>", %"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" addrspace(4)* %0, i32 0, i32 0
-
-
- ; CHECK-LLVM: %[[PIPE_STORAGE_1:[0-9]+]] = load %spirv.PipeStorage addrspace(1)*, %spirv.PipeStorage addrspace(1)* addrspace(4)* %[[ID1]], align 4
- ; CHECK-LLVM: %[[WRITE_PIPE:[0-9]+]] = call spir_func %spirv.Pipe._1 addrspace(1)* @_Z39__spirv_CreatePipeFromPipeStorage_writePU3AS119__spirv_PipeStorage(%spirv.PipeStorage addrspace(1)* %[[PIPE_STORAGE_1]])
- ; CHECK-LLVM: %[[WRITE_PIPE_WRAPPER:[0-9]+]] = addrspacecast %"[[CL_WRITE_PIPE_NAME]]"* %mywpipe to %"[[CL_WRITE_PIPE_NAME]]" addrspace(4)*
- ; CHECK-LLVM: call spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE1EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE1EEE(%"[[CL_WRITE_PIPE_NAME]]" addrspace(4)* nocapture %[[WRITE_PIPE_WRAPPER]], %spirv.Pipe._1 addrspace(1)* %[[WRITE_PIPE]])
-
- ; CHECK-SPIRV: Load {{[0-9]+}} [[PIPE_STORAGE_ID0:[0-9]+]] [[SPIRV1]] 2 4
- ; CHECK-SPIRV: CreatePipeFromPipeStorage [[WRITE_PIPE]] [[WRITE_PIPE_ID:[0-9]+]] [[PIPE_STORAGE_ID0]]
- ; CHECK-SPIRV: PtrCastToGeneric {{[0-9]+}} [[GENERIC_WRITE_PIPE_WRAPPER_ID:[0-9]+]] [[WRITE_PIPE_WRAPPER_ID]]
- ; CHECK-SPIRV: FunctionCall {{[0-9]+}} {{[0-9]+}} [[WRITE_PIPE_WRAPPER_CTOR]] [[GENERIC_WRITE_PIPE_WRAPPER_ID]] [[WRITE_PIPE_ID]]
-
- %2 = load %spirv.PipeStorage addrspace(1)*, %spirv.PipeStorage addrspace(1)* addrspace(4)* %1, align 4
- %3 = tail call spir_func %spirv.Pipe._1 addrspace(1)* @_Z39__spirv_CreatePipeFromPipeStorage_writePU3AS1K19__spirv_PipeStorage(%spirv.PipeStorage addrspace(1)* %2)
- %4 = addrspacecast %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>"* %mywpipe to %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" addrspace(4)*
- call spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE1EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE1EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" addrspace(4)* %4, %spirv.Pipe._1 addrspace(1)* %3)
-
-
- ; CHECK-LLVM: %[[PIPE_STORAGE_2:[0-9]+]] = load %spirv.PipeStorage addrspace(1)*, %spirv.PipeStorage addrspace(1)* addrspace(4)* %[[ID1]], align 4
- ; CHECK-LLVM: %[[READ_PIPE:[0-9]+]] = call spir_func %spirv.Pipe._0 addrspace(1)* @_Z38__spirv_CreatePipeFromPipeStorage_readPU3AS119__spirv_PipeStorage(%spirv.PipeStorage addrspace(1)* %[[PIPE_STORAGE_2]])
- ; CHECK-LLVM: %[[READ_PIPE_WRAPPER:[0-9]+]] = addrspacecast %"[[CL_READ_PIPE_NAME]]"* %myrpipe to %"[[CL_READ_PIPE_NAME]]" addrspace(4)*
- ; CHECK-LLVM: call spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE0EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE0EEE(%"[[CL_READ_PIPE_NAME]]" addrspace(4)* nocapture %[[READ_PIPE_WRAPPER]], %spirv.Pipe._0 addrspace(1)* %[[READ_PIPE]])
-
- ; CHECK-SPIRV: Load {{[0-9]+}} [[PIPE_STORAGE_ID1:[0-9]+]] [[SPIRV1]] 2 4
- ; CHECK-SPIRV: CreatePipeFromPipeStorage [[READ_PIPE]] [[READ_PIPE_ID:[0-9]+]] [[PIPE_STORAGE_ID1]]
- ; CHECK-SPIRV: PtrCastToGeneric {{[0-9]+}} [[GENERIC_READ_PIPE_WRAPPER_ID:[0-9]+]] [[READ_PIPE_WRAPPER_ID]]
- ; CHECK-SPIRV: FunctionCall {{[0-9]+}} {{[0-9]+}} [[READ_PIPE_WRAPPER_CTOR]] [[GENERIC_READ_PIPE_WRAPPER_ID]] [[READ_PIPE_ID]]
-
- %5 = load %spirv.PipeStorage addrspace(1)*, %spirv.PipeStorage addrspace(1)* addrspace(4)* %1, align 4
- %6 = tail call spir_func %spirv.Pipe._0 addrspace(1)* @_Z38__spirv_CreatePipeFromPipeStorage_readPU3AS1K19__spirv_PipeStorage(%spirv.PipeStorage addrspace(1)* %5)
- %7 = addrspacecast %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>"* %myrpipe to %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" addrspace(4)*
- call spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE0EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE0EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" addrspace(4)* %7, %spirv.Pipe._0 addrspace(1)* %6)
-
-
- ret void
-}
-
-; Function Attrs: nounwind
-define linkonce_odr spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE0EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE0EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" addrspace(4)* nocapture %this, %spirv.Pipe._0 addrspace(1)* %handle) unnamed_addr align 2 {
-entry:
- tail call spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE0EEC2EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE0EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" addrspace(4)* %this, %spirv.Pipe._0 addrspace(1)* %handle)
- ret void
-}
-
-; Function Attrs: nounwind
-define linkonce_odr spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE0EEC2EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE0EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" addrspace(4)* nocapture %this, %spirv.Pipe._0 addrspace(1)* %handle) unnamed_addr align 2 {
-entry:
- %_handle = getelementptr inbounds %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>", %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" addrspace(4)* %this, i32 0, i32 0
- store %spirv.Pipe._0 addrspace(1)* %handle, %spirv.Pipe._0 addrspace(1)* addrspace(4)* %_handle, align 4, !tbaa !11
- ret void
-}
-
-; Function Attrs: nounwind
-declare spir_func %spirv.Pipe._0 addrspace(1)* @_Z38__spirv_CreatePipeFromPipeStorage_readPU3AS1K19__spirv_PipeStorage(%spirv.PipeStorage addrspace(1)*)
-
-; Function Attrs: nounwind
-define linkonce_odr spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE1EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE1EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" addrspace(4)* nocapture %this, %spirv.Pipe._1 addrspace(1)* %handle) unnamed_addr align 2 {
-entry:
- tail call spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE1EEC2EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE1EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" addrspace(4)* %this, %spirv.Pipe._1 addrspace(1)* %handle)
- ret void
-}
-
-; Function Attrs: nounwind
-define linkonce_odr spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE1EEC2EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE1EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" addrspace(4)* nocapture %this, %spirv.Pipe._1 addrspace(1)* %handle) unnamed_addr align 2 {
-entry:
- %_handle = getelementptr inbounds %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>", %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" addrspace(4)* %this, i32 0, i32 0
- store %spirv.Pipe._1 addrspace(1)* %handle, %spirv.Pipe._1 addrspace(1)* addrspace(4)* %_handle, align 4, !tbaa !13
- ret void
-}
-
-; Function Attrs: nounwind
-declare spir_func %spirv.Pipe._1 addrspace(1)* @_Z39__spirv_CreatePipeFromPipeStorage_writePU3AS1K19__spirv_PipeStorage(%spirv.PipeStorage addrspace(1)*)
-
-!opencl.enable.FP_CONTRACT = !{}
-!opencl.spir.version = !{!0}
-!opencl.ocl.version = !{!1}
-!opencl.used.extensions = !{!2}
-!opencl.used.optional.core.features = !{!2}
-!opencl.compiler.options = !{!2}
-!llvm.ident = !{!3}
-!spirv.Source = !{!4}
-!spirv.String = !{}
-
-!0 = !{i32 1, i32 2}
-!1 = !{i32 2, i32 2}
-!2 = !{}
-!3 = !{!"clang version 3.6.1 "}
-!4 = !{i32 4, i32 202000}
-!6 = !{!7, !8, i64 0}
-!7 = !{!"_ZTSN2cl12pipe_storageIDv4_iLj1EEE", !8, i64 0}
-!8 = !{!"any pointer", !9, i64 0}
-!9 = !{!"omnipotent char", !10, i64 0}
-!10 = !{!"Simple C/C++ TBAA"}
-!11 = !{!12, !8, i64 0}
-!12 = !{!"_ZTSN2cl4pipeIDv4_iLNS_11pipe_accessE0EEE", !8, i64 0}
-!13 = !{!14, !8, i64 0}
-!14 = !{!"_ZTSN2cl4pipeIDv4_iLNS_11pipe_accessE1EEE", !8, i64 0}
+; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt +; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + + +; CHECK-LLVM: %"[[CL_PIPE_STORAGE_NAME:[^"]+]]" = type { %spirv.PipeStorage addrspace(1)* } +; CHECK-LLVM: %"[[CL_READ_PIPE_NAME:[^"]+read>]]" = type { %spirv.Pipe._0 addrspace(1)* } +; CHECK-LLVM: %spirv.Pipe._0 = type opaque +; CHECK-LLVM: %"[[CL_WRITE_PIPE_NAME:[^"]+write>]]" = type { %spirv.Pipe._1 addrspace(1)* } +; CHECK-LLVM: %spirv.Pipe._1 = type opaque + + +; CHECK-SPIRV: Capability Pipes +; CHECK-SPIRV: Capability PipeStorage + +; CHECK-SPIRV: Name [[PIPE_STORAGE_ID:[0-9]+]] "mygpipe" +; CHECK-SPIRV: Name [[READ_PIPE_WRAPPER_ID:[0-9]+]] "myrpipe" +; CHECK-SPIRV: Name [[WRITE_PIPE_WRAPPER_ID:[0-9]+]] "mywpipe" +; CHECK-SPIRV: Name [[WRITE_PIPE_WRAPPER_CTOR:[0-9]+]] "_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE1EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE1EEE" +; CHECK-SPIRV: Name [[READ_PIPE_WRAPPER_CTOR:[0-9]+]] "_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE0EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE0EEE" + +; CHECK-SPIRV: TypeInt [[INT_T:[0-9]+]] 32 0 +; CHECK-SPIRV: Constant [[INT_T]] [[CONSTANT_ZERO_ID:[0-9]+]] 0 + +; CHECK-SPIRV: TypePipe [[READ_PIPE:[0-9]+]] 0 +; CHECK-SPIRV: TypeStruct [[READ_PIPE_WRAPPER:[0-9]+]] [[READ_PIPE]] +; CHECK-SPIRV: TypePointer [[READ_PIPE_WRAPPER_PTR:[0-9]+]] 7 [[READ_PIPE_WRAPPER]] +; CHECK-SPIRV: TypePipe [[WRITE_PIPE:[0-9]+]] 1 +; CHECK-SPIRV: TypeStruct [[WRITE_PIPE_WRAPPER:[0-9]+]] [[WRITE_PIPE]] + +; CHECK-SPIRV: TypePointer [[WRITE_PIPE_WRAPPER_PTR:[0-9]+]] 7 [[WRITE_PIPE_WRAPPER]] + + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir-unknown-unknown" + +%spirv.ConstantPipeStorage = type { i32, i32, i32 } +%"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" = type { %spirv.PipeStorage addrspace(1)* } +%spirv.PipeStorage = type opaque +%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" = type { %spirv.Pipe._0 addrspace(1)* } +%spirv.Pipe._0 = type opaque +%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" = type { %spirv.Pipe._1 addrspace(1)* } +%spirv.Pipe._1 = type opaque + +@_ZN2cl9__details29OpConstantPipeStorage_CreatorILi16ELi16ELi1EE5valueE = linkonce_odr addrspace(1) global %spirv.ConstantPipeStorage { i32 16, i32 16, i32 1 }, align 4 +@mygpipe = addrspace(1) global %"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" { %spirv.PipeStorage addrspace(1)* bitcast (%spirv.ConstantPipeStorage addrspace(1)* @_ZN2cl9__details29OpConstantPipeStorage_CreatorILi16ELi16ELi1EE5valueE to %spirv.PipeStorage addrspace(1)*) }, align 4 + + +; Function Attrs: nounwind +define spir_kernel void @worker() { +entry: + ; CHECK-LLVM: %myrpipe = alloca %"[[CL_READ_PIPE_NAME]]", align 4 + ; CHECK-LLVM: %mywpipe = alloca %"[[CL_WRITE_PIPE_NAME]]", align 4 + + ; CHECK-SPIRV: Variable [[READ_PIPE_WRAPPER_PTR]] [[READ_PIPE_WRAPPER_ID]] 7 + ; CHECK-SPIRV: Variable [[WRITE_PIPE_WRAPPER_PTR]] [[WRITE_PIPE_WRAPPER_ID]] 7 + + %myrpipe = alloca %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>", align 4 + %mywpipe = alloca %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>", align 4 + + + ; CHECK-LLVM: %[[ID0:[0-9]+]] = addrspacecast %"[[CL_PIPE_STORAGE_NAME]]" addrspace(1)* @mygpipe to %"[[CL_PIPE_STORAGE_NAME]]" addrspace(4)* + ; CHECK-LLVM: %[[ID1:[0-9]+]] = getelementptr %"[[CL_PIPE_STORAGE_NAME]]", %"[[CL_PIPE_STORAGE_NAME]]" addrspace(4)* %[[ID0]], i32 0, i32 0 + + ; CHECK-SPIRV: PtrCastToGeneric {{[0-9]+}} [[SPIRV0:[0-9]+]] [[PIPE_STORAGE_ID]] + ; CHECK-SPIRV: PtrAccessChain {{[0-9]+}} [[SPIRV1:[0-9]+]] [[SPIRV0]] [[CONSTANT_ZERO_ID]] [[CONSTANT_ZERO_ID]] + + %0 = addrspacecast %"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" addrspace(1)* @mygpipe to %"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" addrspace(4)* + %1 = getelementptr %"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>", %"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" addrspace(4)* %0, i32 0, i32 0 + + + ; CHECK-LLVM: %[[PIPE_STORAGE_1:[0-9]+]] = load %spirv.PipeStorage addrspace(1)*, %spirv.PipeStorage addrspace(1)* addrspace(4)* %[[ID1]], align 4 + ; CHECK-LLVM: %[[WRITE_PIPE:[0-9]+]] = call spir_func %spirv.Pipe._1 addrspace(1)* @_Z39__spirv_CreatePipeFromPipeStorage_writePU3AS119__spirv_PipeStorage(%spirv.PipeStorage addrspace(1)* %[[PIPE_STORAGE_1]]) + ; CHECK-LLVM: %[[WRITE_PIPE_WRAPPER:[0-9]+]] = addrspacecast %"[[CL_WRITE_PIPE_NAME]]"* %mywpipe to %"[[CL_WRITE_PIPE_NAME]]" addrspace(4)* + ; CHECK-LLVM: call spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE1EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE1EEE(%"[[CL_WRITE_PIPE_NAME]]" addrspace(4)* nocapture %[[WRITE_PIPE_WRAPPER]], %spirv.Pipe._1 addrspace(1)* %[[WRITE_PIPE]]) + + ; CHECK-SPIRV: Load {{[0-9]+}} [[PIPE_STORAGE_ID0:[0-9]+]] [[SPIRV1]] 2 4 + ; CHECK-SPIRV: CreatePipeFromPipeStorage [[WRITE_PIPE]] [[WRITE_PIPE_ID:[0-9]+]] [[PIPE_STORAGE_ID0]] + ; CHECK-SPIRV: PtrCastToGeneric {{[0-9]+}} [[GENERIC_WRITE_PIPE_WRAPPER_ID:[0-9]+]] [[WRITE_PIPE_WRAPPER_ID]] + ; CHECK-SPIRV: FunctionCall {{[0-9]+}} {{[0-9]+}} [[WRITE_PIPE_WRAPPER_CTOR]] [[GENERIC_WRITE_PIPE_WRAPPER_ID]] [[WRITE_PIPE_ID]] + + %2 = load %spirv.PipeStorage addrspace(1)*, %spirv.PipeStorage addrspace(1)* addrspace(4)* %1, align 4 + %3 = tail call spir_func %spirv.Pipe._1 addrspace(1)* @_Z39__spirv_CreatePipeFromPipeStorage_writePU3AS1K19__spirv_PipeStorage(%spirv.PipeStorage addrspace(1)* %2) + %4 = addrspacecast %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>"* %mywpipe to %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" addrspace(4)* + call spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE1EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE1EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" addrspace(4)* %4, %spirv.Pipe._1 addrspace(1)* %3) + + + ; CHECK-LLVM: %[[PIPE_STORAGE_2:[0-9]+]] = load %spirv.PipeStorage addrspace(1)*, %spirv.PipeStorage addrspace(1)* addrspace(4)* %[[ID1]], align 4 + ; CHECK-LLVM: %[[READ_PIPE:[0-9]+]] = call spir_func %spirv.Pipe._0 addrspace(1)* @_Z38__spirv_CreatePipeFromPipeStorage_readPU3AS119__spirv_PipeStorage(%spirv.PipeStorage addrspace(1)* %[[PIPE_STORAGE_2]]) + ; CHECK-LLVM: %[[READ_PIPE_WRAPPER:[0-9]+]] = addrspacecast %"[[CL_READ_PIPE_NAME]]"* %myrpipe to %"[[CL_READ_PIPE_NAME]]" addrspace(4)* + ; CHECK-LLVM: call spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE0EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE0EEE(%"[[CL_READ_PIPE_NAME]]" addrspace(4)* nocapture %[[READ_PIPE_WRAPPER]], %spirv.Pipe._0 addrspace(1)* %[[READ_PIPE]]) + + ; CHECK-SPIRV: Load {{[0-9]+}} [[PIPE_STORAGE_ID1:[0-9]+]] [[SPIRV1]] 2 4 + ; CHECK-SPIRV: CreatePipeFromPipeStorage [[READ_PIPE]] [[READ_PIPE_ID:[0-9]+]] [[PIPE_STORAGE_ID1]] + ; CHECK-SPIRV: PtrCastToGeneric {{[0-9]+}} [[GENERIC_READ_PIPE_WRAPPER_ID:[0-9]+]] [[READ_PIPE_WRAPPER_ID]] + ; CHECK-SPIRV: FunctionCall {{[0-9]+}} {{[0-9]+}} [[READ_PIPE_WRAPPER_CTOR]] [[GENERIC_READ_PIPE_WRAPPER_ID]] [[READ_PIPE_ID]] + + %5 = load %spirv.PipeStorage addrspace(1)*, %spirv.PipeStorage addrspace(1)* addrspace(4)* %1, align 4 + %6 = tail call spir_func %spirv.Pipe._0 addrspace(1)* @_Z38__spirv_CreatePipeFromPipeStorage_readPU3AS1K19__spirv_PipeStorage(%spirv.PipeStorage addrspace(1)* %5) + %7 = addrspacecast %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>"* %myrpipe to %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" addrspace(4)* + call spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE0EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE0EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" addrspace(4)* %7, %spirv.Pipe._0 addrspace(1)* %6) + + + ret void +} + +; Function Attrs: nounwind +define linkonce_odr spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE0EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE0EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" addrspace(4)* nocapture %this, %spirv.Pipe._0 addrspace(1)* %handle) unnamed_addr align 2 { +entry: + tail call spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE0EEC2EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE0EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" addrspace(4)* %this, %spirv.Pipe._0 addrspace(1)* %handle) + ret void +} + +; Function Attrs: nounwind +define linkonce_odr spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE0EEC2EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE0EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" addrspace(4)* nocapture %this, %spirv.Pipe._0 addrspace(1)* %handle) unnamed_addr align 2 { +entry: + %_handle = getelementptr inbounds %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>", %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::read>" addrspace(4)* %this, i32 0, i32 0 + store %spirv.Pipe._0 addrspace(1)* %handle, %spirv.Pipe._0 addrspace(1)* addrspace(4)* %_handle, align 4, !tbaa !11 + ret void +} + +; Function Attrs: nounwind +declare spir_func %spirv.Pipe._0 addrspace(1)* @_Z38__spirv_CreatePipeFromPipeStorage_readPU3AS1K19__spirv_PipeStorage(%spirv.PipeStorage addrspace(1)*) + +; Function Attrs: nounwind +define linkonce_odr spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE1EEC1EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE1EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" addrspace(4)* nocapture %this, %spirv.Pipe._1 addrspace(1)* %handle) unnamed_addr align 2 { +entry: + tail call spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE1EEC2EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE1EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" addrspace(4)* %this, %spirv.Pipe._1 addrspace(1)* %handle) + ret void +} + +; Function Attrs: nounwind +define linkonce_odr spir_func void @_ZNU3AS42cl4pipeIDv4_iLNS_11pipe_accessE1EEC2EPU3AS1NS_7__spirv10OpTypePipeILNS3_15AccessQualifierE1EEE(%"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" addrspace(4)* nocapture %this, %spirv.Pipe._1 addrspace(1)* %handle) unnamed_addr align 2 { +entry: + %_handle = getelementptr inbounds %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>", %"class.cl::pipe<int __attribute__((ext_vector_type(4))), cl::pipe_access::write>" addrspace(4)* %this, i32 0, i32 0 + store %spirv.Pipe._1 addrspace(1)* %handle, %spirv.Pipe._1 addrspace(1)* addrspace(4)* %_handle, align 4, !tbaa !13 + ret void +} + +; Function Attrs: nounwind +declare spir_func %spirv.Pipe._1 addrspace(1)* @_Z39__spirv_CreatePipeFromPipeStorage_writePU3AS1K19__spirv_PipeStorage(%spirv.PipeStorage addrspace(1)*) + +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!0} +!opencl.ocl.version = !{!1} +!opencl.used.extensions = !{!2} +!opencl.used.optional.core.features = !{!2} +!opencl.compiler.options = !{!2} +!llvm.ident = !{!3} +!spirv.Source = !{!4} +!spirv.String = !{} + +!0 = !{i32 1, i32 2} +!1 = !{i32 2, i32 2} +!2 = !{} +!3 = !{!"clang version 3.6.1 "} +!4 = !{i32 4, i32 202000} +!6 = !{!7, !8, i64 0} +!7 = !{!"_ZTSN2cl12pipe_storageIDv4_iLj1EEE", !8, i64 0} +!8 = !{!"any pointer", !9, i64 0} +!9 = !{!"omnipotent char", !10, i64 0} +!10 = !{!"Simple C/C++ TBAA"} +!11 = !{!12, !8, i64 0} +!12 = !{!"_ZTSN2cl4pipeIDv4_iLNS_11pipe_accessE0EEE", !8, i64 0} +!13 = !{!14, !8, i64 0} +!14 = !{!"_ZTSN2cl4pipeIDv4_iLNS_11pipe_accessE1EEE", !8, i64 0} diff --git a/test/ExecutionMode.ll b/test/ExecutionMode.ll index 309595e..9858342 100644 --- a/test/ExecutionMode.ll +++ b/test/ExecutionMode.ll @@ -1,150 +1,150 @@ -; RUN: llvm-as < %s | llvm-spirv -spirv-text -o %t
-; RUN: FileCheck < %t %s
-
-; check for magic number followed by version 1.1
-; CHECK: 119734787 65792
-
-; CHECK-DAG: TypeVoid [[VOID:[0-9]+]]
-
-; CHECK-DAG: EntryPoint 6 [[WORKER:[0-9]+]] "worker"
-; CHECK-DAG: EntryPoint 6 [[INIT:[0-9]+]] "_SPIRV_GLOBAL__I_45b04794_Test_attr.cl"
-; CHECK-DAG: EntryPoint 6 [[FIN:[0-9]+]] "_SPIRV_GLOBAL__D_45b04794_Test_attr.cl"
-
-; CHECK-DAG: ExecutionMode [[WORKER]] 17 10 10 10
-; CHECK-DAG: ExecutionMode [[WORKER]] 18 12 10 1
-; CHECK-DAG: ExecutionMode [[WORKER]] 30 262149
-; CHECK-DAG: ExecutionMode [[WORKER]] 36 4
-; CHECK-DAG: ExecutionMode [[INIT]] 17 1 1 1
-; CHECK-DAG: ExecutionMode [[INIT]] 33
-; CHECK-DAG: ExecutionMode [[FIN]] 17 1 1 1
-; CHECK-DAG: ExecutionMode [[FIN]] 34
-
-target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir-unknown-unknown"
-
-%struct.global_ctor_dtor = type { i32 }
-
-@g = addrspace(1) global %struct.global_ctor_dtor zeroinitializer, align 4
-
-; Function Attrs: nounwind
-define internal spir_func void @__cxx_global_var_init() #0 {
-entry:
- call spir_func void @_ZNU3AS416global_ctor_dtorC1Ei(%struct.global_ctor_dtor addrspace(4)* addrspacecast (%struct.global_ctor_dtor addrspace(1)* @g to %struct.global_ctor_dtor addrspace(4)*), i32 12)
- ret void
-}
-
-; Function Attrs: nounwind
-define linkonce_odr spir_func void @_ZNU3AS416global_ctor_dtorC1Ei(%struct.global_ctor_dtor addrspace(4)* %this, i32 %i) unnamed_addr #1 align 2 {
-entry:
- %this.addr = alloca %struct.global_ctor_dtor addrspace(4)*, align 4
- %i.addr = alloca i32, align 4
- store %struct.global_ctor_dtor addrspace(4)* %this, %struct.global_ctor_dtor addrspace(4)** %this.addr, align 4
- store i32 %i, i32* %i.addr, align 4
- %this1 = load %struct.global_ctor_dtor addrspace(4)*, %struct.global_ctor_dtor addrspace(4)** %this.addr
- %0 = load i32, i32* %i.addr, align 4
- call spir_func void @_ZNU3AS416global_ctor_dtorC2Ei(%struct.global_ctor_dtor addrspace(4)* %this1, i32 %0)
- ret void
-}
-
-; Function Attrs: nounwind
-define linkonce_odr spir_func void @_ZNU3AS416global_ctor_dtorD1Ev(%struct.global_ctor_dtor addrspace(4)* %this) unnamed_addr #1 align 2 {
-entry:
- %this.addr = alloca %struct.global_ctor_dtor addrspace(4)*, align 4
- store %struct.global_ctor_dtor addrspace(4)* %this, %struct.global_ctor_dtor addrspace(4)** %this.addr, align 4
- %this1 = load %struct.global_ctor_dtor addrspace(4)*, %struct.global_ctor_dtor addrspace(4)** %this.addr
- call spir_func void @_ZNU3AS416global_ctor_dtorD2Ev(%struct.global_ctor_dtor addrspace(4)* %this1) #0
- ret void
-}
-
-; Function Attrs: nounwind
-define internal spir_func void @__dtor_g() #0 {
-entry:
- call spir_func void @_ZNU3AS416global_ctor_dtorD1Ev(%struct.global_ctor_dtor addrspace(4)* addrspacecast (%struct.global_ctor_dtor addrspace(1)* @g to %struct.global_ctor_dtor addrspace(4)*))
- ret void
-}
-
-; CHECK: Function [[VOID]] [[WORKER]]
-
-; Function Attrs: nounwind
-define spir_kernel void @worker() #1 {
-entry:
- ret void
-}
-
-; Function Attrs: nounwind
-define linkonce_odr spir_func void @_ZNU3AS416global_ctor_dtorD2Ev(%struct.global_ctor_dtor addrspace(4)* %this) unnamed_addr #1 align 2 {
-entry:
- %this.addr = alloca %struct.global_ctor_dtor addrspace(4)*, align 4
- store %struct.global_ctor_dtor addrspace(4)* %this, %struct.global_ctor_dtor addrspace(4)** %this.addr, align 4
- %this1 = load %struct.global_ctor_dtor addrspace(4)*, %struct.global_ctor_dtor addrspace(4)** %this.addr
- %a = getelementptr inbounds %struct.global_ctor_dtor, %struct.global_ctor_dtor addrspace(4)* %this1, i32 0, i32 0
- store i32 0, i32 addrspace(4)* %a, align 4
- ret void
-}
-
-; Function Attrs: nounwind
-define linkonce_odr spir_func void @_ZNU3AS416global_ctor_dtorC2Ei(%struct.global_ctor_dtor addrspace(4)* %this, i32 %i) unnamed_addr #1 align 2 {
-entry:
- %this.addr = alloca %struct.global_ctor_dtor addrspace(4)*, align 4
- %i.addr = alloca i32, align 4
- store %struct.global_ctor_dtor addrspace(4)* %this, %struct.global_ctor_dtor addrspace(4)** %this.addr, align 4
- store i32 %i, i32* %i.addr, align 4
- %this1 = load %struct.global_ctor_dtor addrspace(4)*, %struct.global_ctor_dtor addrspace(4)** %this.addr
- %0 = load i32, i32* %i.addr, align 4
- %a = getelementptr inbounds %struct.global_ctor_dtor, %struct.global_ctor_dtor addrspace(4)* %this1, i32 0, i32 0
- store i32 %0, i32 addrspace(4)* %a, align 4
- ret void
-}
-
-; Function Attrs: nounwind
-define internal spir_func void @_GLOBAL__sub_I_Test_attr.cl() #0 {
-entry:
- call spir_func void @__cxx_global_var_init()
- ret void
-}
-
-; CHECK: Function [[VOID]] [[INIT]]
-
-; Function Attrs: noinline nounwind
-define spir_kernel void @_SPIRV_GLOBAL__I_45b04794_Test_attr.cl() #2 {
-entry:
- call spir_func void @_GLOBAL__sub_I_Test_attr.cl()
- ret void
-}
-
-; CHECK: Function [[VOID]] [[FIN]]
-
-; Function Attrs: noinline nounwind
-define spir_kernel void @_SPIRV_GLOBAL__D_45b04794_Test_attr.cl() #2 {
-entry:
- call spir_func void @__dtor_g()
- ret void
-}
-
-attributes #0 = { nounwind }
-attributes #1 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #2 = { noinline nounwind }
-
-!spirv.ExecutionMode = !{!0, !1, !2, !3, !4, !5, !6, !7}
-!opencl.enable.FP_CONTRACT = !{}
-!opencl.spir.version = !{!8}
-!opencl.ocl.version = !{!9}
-!opencl.used.extensions = !{!10}
-!opencl.used.optional.core.features = !{!10}
-!opencl.compiler.options = !{!10}
-!llvm.ident = !{!11}
-!spirv.Source = !{!12}
-
-!0 = !{void ()* @worker, i32 30, i32 262149}
-!1 = !{void ()* @worker, i32 18, i32 12, i32 10, i32 1}
-!2 = !{void ()* @worker, i32 17, i32 10, i32 10, i32 10}
-!3 = !{void ()* @worker, i32 36, i32 4}
-!4 = !{void ()* @_SPIRV_GLOBAL__I_45b04794_Test_attr.cl, i32 33}
-!5 = !{void ()* @_SPIRV_GLOBAL__I_45b04794_Test_attr.cl, i32 17, i32 1, i32 1, i32 1}
-!6 = !{void ()* @_SPIRV_GLOBAL__D_45b04794_Test_attr.cl, i32 34}
-!7 = !{void ()* @_SPIRV_GLOBAL__D_45b04794_Test_attr.cl, i32 17, i32 1, i32 1, i32 1}
-!8 = !{i32 1, i32 2}
-!9 = !{i32 2, i32 2}
-!10 = !{}
-!11 = !{!"clang version 3.6.1 "}
-!12 = !{i32 4, i32 202000}
+; RUN: llvm-as < %s | llvm-spirv -spirv-text -o %t +; RUN: FileCheck < %t %s + +; check for magic number followed by version 1.1 +; CHECK: 119734787 65792 + +; CHECK-DAG: TypeVoid [[VOID:[0-9]+]] + +; CHECK-DAG: EntryPoint 6 [[WORKER:[0-9]+]] "worker" +; CHECK-DAG: EntryPoint 6 [[INIT:[0-9]+]] "_SPIRV_GLOBAL__I_45b04794_Test_attr.cl" +; CHECK-DAG: EntryPoint 6 [[FIN:[0-9]+]] "_SPIRV_GLOBAL__D_45b04794_Test_attr.cl" + +; CHECK-DAG: ExecutionMode [[WORKER]] 17 10 10 10 +; CHECK-DAG: ExecutionMode [[WORKER]] 18 12 10 1 +; CHECK-DAG: ExecutionMode [[WORKER]] 30 262149 +; CHECK-DAG: ExecutionMode [[WORKER]] 36 4 +; CHECK-DAG: ExecutionMode [[INIT]] 17 1 1 1 +; CHECK-DAG: ExecutionMode [[INIT]] 33 +; CHECK-DAG: ExecutionMode [[FIN]] 17 1 1 1 +; CHECK-DAG: ExecutionMode [[FIN]] 34 + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir-unknown-unknown" + +%struct.global_ctor_dtor = type { i32 } + +@g = addrspace(1) global %struct.global_ctor_dtor zeroinitializer, align 4 + +; Function Attrs: nounwind +define internal spir_func void @__cxx_global_var_init() #0 { +entry: + call spir_func void @_ZNU3AS416global_ctor_dtorC1Ei(%struct.global_ctor_dtor addrspace(4)* addrspacecast (%struct.global_ctor_dtor addrspace(1)* @g to %struct.global_ctor_dtor addrspace(4)*), i32 12) + ret void +} + +; Function Attrs: nounwind +define linkonce_odr spir_func void @_ZNU3AS416global_ctor_dtorC1Ei(%struct.global_ctor_dtor addrspace(4)* %this, i32 %i) unnamed_addr #1 align 2 { +entry: + %this.addr = alloca %struct.global_ctor_dtor addrspace(4)*, align 4 + %i.addr = alloca i32, align 4 + store %struct.global_ctor_dtor addrspace(4)* %this, %struct.global_ctor_dtor addrspace(4)** %this.addr, align 4 + store i32 %i, i32* %i.addr, align 4 + %this1 = load %struct.global_ctor_dtor addrspace(4)*, %struct.global_ctor_dtor addrspace(4)** %this.addr + %0 = load i32, i32* %i.addr, align 4 + call spir_func void @_ZNU3AS416global_ctor_dtorC2Ei(%struct.global_ctor_dtor addrspace(4)* %this1, i32 %0) + ret void +} + +; Function Attrs: nounwind +define linkonce_odr spir_func void @_ZNU3AS416global_ctor_dtorD1Ev(%struct.global_ctor_dtor addrspace(4)* %this) unnamed_addr #1 align 2 { +entry: + %this.addr = alloca %struct.global_ctor_dtor addrspace(4)*, align 4 + store %struct.global_ctor_dtor addrspace(4)* %this, %struct.global_ctor_dtor addrspace(4)** %this.addr, align 4 + %this1 = load %struct.global_ctor_dtor addrspace(4)*, %struct.global_ctor_dtor addrspace(4)** %this.addr + call spir_func void @_ZNU3AS416global_ctor_dtorD2Ev(%struct.global_ctor_dtor addrspace(4)* %this1) #0 + ret void +} + +; Function Attrs: nounwind +define internal spir_func void @__dtor_g() #0 { +entry: + call spir_func void @_ZNU3AS416global_ctor_dtorD1Ev(%struct.global_ctor_dtor addrspace(4)* addrspacecast (%struct.global_ctor_dtor addrspace(1)* @g to %struct.global_ctor_dtor addrspace(4)*)) + ret void +} + +; CHECK: Function [[VOID]] [[WORKER]] + +; Function Attrs: nounwind +define spir_kernel void @worker() #1 { +entry: + ret void +} + +; Function Attrs: nounwind +define linkonce_odr spir_func void @_ZNU3AS416global_ctor_dtorD2Ev(%struct.global_ctor_dtor addrspace(4)* %this) unnamed_addr #1 align 2 { +entry: + %this.addr = alloca %struct.global_ctor_dtor addrspace(4)*, align 4 + store %struct.global_ctor_dtor addrspace(4)* %this, %struct.global_ctor_dtor addrspace(4)** %this.addr, align 4 + %this1 = load %struct.global_ctor_dtor addrspace(4)*, %struct.global_ctor_dtor addrspace(4)** %this.addr + %a = getelementptr inbounds %struct.global_ctor_dtor, %struct.global_ctor_dtor addrspace(4)* %this1, i32 0, i32 0 + store i32 0, i32 addrspace(4)* %a, align 4 + ret void +} + +; Function Attrs: nounwind +define linkonce_odr spir_func void @_ZNU3AS416global_ctor_dtorC2Ei(%struct.global_ctor_dtor addrspace(4)* %this, i32 %i) unnamed_addr #1 align 2 { +entry: + %this.addr = alloca %struct.global_ctor_dtor addrspace(4)*, align 4 + %i.addr = alloca i32, align 4 + store %struct.global_ctor_dtor addrspace(4)* %this, %struct.global_ctor_dtor addrspace(4)** %this.addr, align 4 + store i32 %i, i32* %i.addr, align 4 + %this1 = load %struct.global_ctor_dtor addrspace(4)*, %struct.global_ctor_dtor addrspace(4)** %this.addr + %0 = load i32, i32* %i.addr, align 4 + %a = getelementptr inbounds %struct.global_ctor_dtor, %struct.global_ctor_dtor addrspace(4)* %this1, i32 0, i32 0 + store i32 %0, i32 addrspace(4)* %a, align 4 + ret void +} + +; Function Attrs: nounwind +define internal spir_func void @_GLOBAL__sub_I_Test_attr.cl() #0 { +entry: + call spir_func void @__cxx_global_var_init() + ret void +} + +; CHECK: Function [[VOID]] [[INIT]] + +; Function Attrs: noinline nounwind +define spir_kernel void @_SPIRV_GLOBAL__I_45b04794_Test_attr.cl() #2 { +entry: + call spir_func void @_GLOBAL__sub_I_Test_attr.cl() + ret void +} + +; CHECK: Function [[VOID]] [[FIN]] + +; Function Attrs: noinline nounwind +define spir_kernel void @_SPIRV_GLOBAL__D_45b04794_Test_attr.cl() #2 { +entry: + call spir_func void @__dtor_g() + ret void +} + +attributes #0 = { nounwind } +attributes #1 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { noinline nounwind } + +!spirv.ExecutionMode = !{!0, !1, !2, !3, !4, !5, !6, !7} +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!8} +!opencl.ocl.version = !{!9} +!opencl.used.extensions = !{!10} +!opencl.used.optional.core.features = !{!10} +!opencl.compiler.options = !{!10} +!llvm.ident = !{!11} +!spirv.Source = !{!12} + +!0 = !{void ()* @worker, i32 30, i32 262149} +!1 = !{void ()* @worker, i32 18, i32 12, i32 10, i32 1} +!2 = !{void ()* @worker, i32 17, i32 10, i32 10, i32 10} +!3 = !{void ()* @worker, i32 36, i32 4} +!4 = !{void ()* @_SPIRV_GLOBAL__I_45b04794_Test_attr.cl, i32 33} +!5 = !{void ()* @_SPIRV_GLOBAL__I_45b04794_Test_attr.cl, i32 17, i32 1, i32 1, i32 1} +!6 = !{void ()* @_SPIRV_GLOBAL__D_45b04794_Test_attr.cl, i32 34} +!7 = !{void ()* @_SPIRV_GLOBAL__D_45b04794_Test_attr.cl, i32 17, i32 1, i32 1, i32 1} +!8 = !{i32 1, i32 2} +!9 = !{i32 2, i32 2} +!10 = !{} +!11 = !{!"clang version 3.6.1 "} +!12 = !{i32 4, i32 202000} diff --git a/test/ExecutionMode_SPIR_to_SPIRV.ll b/test/ExecutionMode_SPIR_to_SPIRV.ll index 960b7f5..b50c795 100644 --- a/test/ExecutionMode_SPIR_to_SPIRV.ll +++ b/test/ExecutionMode_SPIR_to_SPIRV.ll @@ -1,52 +1,52 @@ -; RUN: llvm-as %s -o %t.bc
-; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt
-; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV
-; RUN: llvm-spirv %t.bc -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
-; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; LLVM => SPIRV checks
-; check for magic number followed by version 1.0
-; CHECK-SPIRV: 119734787 65536
-
-; CHECK-SPIRV-DAG: EntryPoint 6 [[WORKER:[0-9]+]] "worker"
-; CHECK-SPIRV-DAG: ExecutionMode [[WORKER]] 18 128 10 1
-
-
-; LLVM => SPIRV => LLVM checks
-; CHECK-LLVM: define spir_kernel void @worker()
-; CHECK-LLVM-SAME: !work_group_size_hint [[WG:![0-9]+]]
-
-; CHECK-LLVM: [[WG]] = !{i32 128, i32 10, i32 1}
-
-target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
-target triple = "spir-unknown-unknown"
-
-; Function Attrs: nounwind
-define spir_kernel void @worker() #0 {
-entry:
- ret void
-}
-
-attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-
-!opencl.kernels = !{!0}
-!opencl.enable.FP_CONTRACT = !{}
-!opencl.spir.version = !{!7}
-!opencl.ocl.version = !{!7}
-!opencl.used.extensions = !{!8}
-!opencl.used.optional.core.features = !{!8}
-!opencl.compiler.options = !{!8}
-!llvm.ident = !{!9}
-
-!0 = !{void ()* @worker, !1, !2, !3, !4, !5, !6}
-!1 = !{!"kernel_arg_addr_space"}
-!2 = !{!"kernel_arg_access_qual"}
-!3 = !{!"kernel_arg_type"}
-!4 = !{!"kernel_arg_base_type"}
-!5 = !{!"kernel_arg_type_qual"}
-!6 = !{!"work_group_size_hint", i32 128, i32 10, i32 1}
-!7 = !{i32 1, i32 2}
-!8 = !{}
-!9 = !{!"clang version 3.6.1 "}
+; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt +; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; LLVM => SPIRV checks +; check for magic number followed by version 1.0 +; CHECK-SPIRV: 119734787 65536 + +; CHECK-SPIRV-DAG: EntryPoint 6 [[WORKER:[0-9]+]] "worker" +; CHECK-SPIRV-DAG: ExecutionMode [[WORKER]] 18 128 10 1 + + +; LLVM => SPIRV => LLVM checks +; CHECK-LLVM: define spir_kernel void @worker() +; CHECK-LLVM-SAME: !work_group_size_hint [[WG:![0-9]+]] + +; CHECK-LLVM: [[WG]] = !{i32 128, i32 10, i32 1} + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64" +target triple = "spir-unknown-unknown" + +; Function Attrs: nounwind +define spir_kernel void @worker() #0 { +entry: + ret void +} + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!opencl.kernels = !{!0} +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!7} +!opencl.ocl.version = !{!7} +!opencl.used.extensions = !{!8} +!opencl.used.optional.core.features = !{!8} +!opencl.compiler.options = !{!8} +!llvm.ident = !{!9} + +!0 = !{void ()* @worker, !1, !2, !3, !4, !5, !6} +!1 = !{!"kernel_arg_addr_space"} +!2 = !{!"kernel_arg_access_qual"} +!3 = !{!"kernel_arg_type"} +!4 = !{!"kernel_arg_base_type"} +!5 = !{!"kernel_arg_type_qual"} +!6 = !{!"work_group_size_hint", i32 128, i32 10, i32 1} +!7 = !{i32 1, i32 2} +!8 = !{} +!9 = !{!"clang version 3.6.1 "} diff --git a/test/FOrdGreaterThanEqual_bool.ll b/test/FOrdGreaterThanEqual_bool.ll index c6efd69..b635d3a 100644 --- a/test/FOrdGreaterThanEqual_bool.ll +++ b/test/FOrdGreaterThanEqual_bool.ll @@ -1,46 +1,46 @@ -; RUN: llvm-as %s -o %t.bc
-; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt
-; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
-
-; CHECK-SPIRV: 5 FOrdGreaterThanEqual
-; CHECK-SPIRV-NOT: Select
-
-; LLVM IR was generated with -cl-std=c++ option
-
-; ModuleID = 'main'
-target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
-target triple = "spir64-unknown-unknown"
-
-; Function Attrs: nounwind
-define spir_kernel void @test(float %op1, float %op2) #0 {
-entry:
- %0 = call spir_func zeroext i1 @_Z28__spirv_FOrdGreaterThanEqualff(float %op1, float %op2) #2
- ret void
-}
-
-; Function Attrs: nounwind readnone
-declare spir_func zeroext i1 @_Z28__spirv_FOrdGreaterThanEqualff(float, float) #1
-
-attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #1 = { nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #2 = { nounwind readnone }
-
-!opencl.kernels = !{!0}
-!opencl.enable.FP_CONTRACT = !{}
-!opencl.spir.version = !{!6}
-!opencl.ocl.version = !{!7}
-!opencl.used.extensions = !{!8}
-!opencl.used.optional.core.features = !{!8}
-!opencl.compiler.options = !{!8}
-!llvm.ident = !{!9}
-
-!0 = !{void (float, float)* @test, !1, !2, !3, !4, !5}
-!1 = !{!"kernel_arg_addr_space", i32 0, i32 0}
-!2 = !{!"kernel_arg_access_qual", !"none", !"none"}
-!3 = !{!"kernel_arg_type", !"float", !"float"}
-!4 = !{!"kernel_arg_base_type", !"float", !"float"}
-!5 = !{!"kernel_arg_type_qual", !"", !""}
-!6 = !{i32 1, i32 2}
-!7 = !{i32 2, i32 0}
-!8 = !{}
+; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt +; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV + +; CHECK-SPIRV: 5 FOrdGreaterThanEqual +; CHECK-SPIRV-NOT: Select + +; LLVM IR was generated with -cl-std=c++ option + +; ModuleID = 'main' +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64" +target triple = "spir64-unknown-unknown" + +; Function Attrs: nounwind +define spir_kernel void @test(float %op1, float %op2) #0 { +entry: + %0 = call spir_func zeroext i1 @_Z28__spirv_FOrdGreaterThanEqualff(float %op1, float %op2) #2 + ret void +} + +; Function Attrs: nounwind readnone +declare spir_func zeroext i1 @_Z28__spirv_FOrdGreaterThanEqualff(float, float) #1 + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } + +!opencl.kernels = !{!0} +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!6} +!opencl.ocl.version = !{!7} +!opencl.used.extensions = !{!8} +!opencl.used.optional.core.features = !{!8} +!opencl.compiler.options = !{!8} +!llvm.ident = !{!9} + +!0 = !{void (float, float)* @test, !1, !2, !3, !4, !5} +!1 = !{!"kernel_arg_addr_space", i32 0, i32 0} +!2 = !{!"kernel_arg_access_qual", !"none", !"none"} +!3 = !{!"kernel_arg_type", !"float", !"float"} +!4 = !{!"kernel_arg_base_type", !"float", !"float"} +!5 = !{!"kernel_arg_type_qual", !"", !""} +!6 = !{i32 1, i32 2} +!7 = !{i32 2, i32 0} +!8 = !{} !9 = !{!"clang version 3.6.1"}
\ No newline at end of file diff --git a/test/OpLoopMergeDontUnroll.spt b/test/OpLoopMergeDontUnroll.spt index 0689925..3246c5e 100644 --- a/test/OpLoopMergeDontUnroll.spt +++ b/test/OpLoopMergeDontUnroll.spt @@ -1,91 +1,91 @@ -119734787 65536 458752 46 0
-2 Capability Addresses
-2 Capability Linkage
-2 Capability Kernel
-2 Capability Int64
-3 MemoryModel 2 2
-11 EntryPoint 6 1 "loop_merge_branch_dont_unroll"
-3 Source 3 102000
-3 Name 2 "res"
-3 Name 3 "in"
-3 Name 4 "rep"
-3 Name 5 "num"
-4 Decorate 6 FuncParamAttr 5
-2 DecorationGroup 6
-4 Decorate 7 BuiltIn 28
-3 Decorate 7 Constant
-11 Decorate 7 LinkageAttributes "__spirv_GlobalInvocationId" Import
-4 GroupDecorate 6 2 3
-4 TypeInt 8 64 0
-4 TypeInt 14 32 1
-5 Constant 8 11 32 0
-4 Constant 14 15 0
-4 Constant 14 16 1
-4 TypeVector 9 8 3
-4 TypePointer 10 0 9
-2 TypeBool 12
-2 TypeVoid 13
-4 TypePointer 17 5 14
-4 TypePointer 18 7 14
-7 TypeFunction 19 13 17 17 14 14
-4 Variable 10 7 0
-
-5 Function 13 1 0 19
-3 FunctionParameter 17 2
-3 FunctionParameter 17 3
-3 FunctionParameter 14 4
-3 FunctionParameter 14 5
-
-2 Label 20
-6 Load 9 21 7 2 0
-5 CompositeExtract 8 22 21 0
-5 ShiftLeftLogical 8 23 22 11
-5 ShiftRightArithmetic 8 24 23 11
-4 SConvert 14 25 24
-4 Variable 18 26 7
-4 Variable 18 27 7
-5 Store 26 15 2 4
-5 Store 27 15 2 4
-2 Branch 28
-
-2 Label 28
-4 LoopMerge 29 30 2
-2 Branch 31
-
-2 Label 31
-4 Load 14 32 27
-5 SLessThan 12 33 32 4
-4 BranchConditional 33 34 29
-
-2 Label 34
-4 Load 14 35 27
-5 IMul 14 36 35 5
-5 IAdd 14 37 25 36
-5 InBoundsPtrAccessChain 17 38 3 37
-4 Load 14 39 38
-4 Load 14 40 26
-5 IAdd 14 41 40 39
-5 Store 26 41 2 4
-2 Branch 30
-
-2 Label 30
-4 Load 14 42 27
-5 IAdd 14 43 42 16
-3 Store 27 43
-2 Branch 28
-
-2 Label 29
-4 Load 14 44 26
-5 InBoundsPtrAccessChain 17 45 2 24
-5 Store 45 44 2 4
-1 Return
-
-1 FunctionEnd
-
-; RUN: llvm-spirv %s -to-binary -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.bc
-; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-LLVM: br label %{{[0-9]+}}, !llvm.loop ![[MD:[0-9]+]]
-; CHECK-LLVM: ![[MD]] = distinct !{![[MD]], ![[MD_unroll_disable:[0-9]+]]}
+119734787 65536 458752 46 0 +2 Capability Addresses +2 Capability Linkage +2 Capability Kernel +2 Capability Int64 +3 MemoryModel 2 2 +11 EntryPoint 6 1 "loop_merge_branch_dont_unroll" +3 Source 3 102000 +3 Name 2 "res" +3 Name 3 "in" +3 Name 4 "rep" +3 Name 5 "num" +4 Decorate 6 FuncParamAttr 5 +2 DecorationGroup 6 +4 Decorate 7 BuiltIn 28 +3 Decorate 7 Constant +11 Decorate 7 LinkageAttributes "__spirv_GlobalInvocationId" Import +4 GroupDecorate 6 2 3 +4 TypeInt 8 64 0 +4 TypeInt 14 32 1 +5 Constant 8 11 32 0 +4 Constant 14 15 0 +4 Constant 14 16 1 +4 TypeVector 9 8 3 +4 TypePointer 10 0 9 +2 TypeBool 12 +2 TypeVoid 13 +4 TypePointer 17 5 14 +4 TypePointer 18 7 14 +7 TypeFunction 19 13 17 17 14 14 +4 Variable 10 7 0 + +5 Function 13 1 0 19 +3 FunctionParameter 17 2 +3 FunctionParameter 17 3 +3 FunctionParameter 14 4 +3 FunctionParameter 14 5 + +2 Label 20 +6 Load 9 21 7 2 0 +5 CompositeExtract 8 22 21 0 +5 ShiftLeftLogical 8 23 22 11 +5 ShiftRightArithmetic 8 24 23 11 +4 SConvert 14 25 24 +4 Variable 18 26 7 +4 Variable 18 27 7 +5 Store 26 15 2 4 +5 Store 27 15 2 4 +2 Branch 28 + +2 Label 28 +4 LoopMerge 29 30 2 +2 Branch 31 + +2 Label 31 +4 Load 14 32 27 +5 SLessThan 12 33 32 4 +4 BranchConditional 33 34 29 + +2 Label 34 +4 Load 14 35 27 +5 IMul 14 36 35 5 +5 IAdd 14 37 25 36 +5 InBoundsPtrAccessChain 17 38 3 37 +4 Load 14 39 38 +4 Load 14 40 26 +5 IAdd 14 41 40 39 +5 Store 26 41 2 4 +2 Branch 30 + +2 Label 30 +4 Load 14 42 27 +5 IAdd 14 43 42 16 +3 Store 27 43 +2 Branch 28 + +2 Label 29 +4 Load 14 44 26 +5 InBoundsPtrAccessChain 17 45 2 24 +5 Store 45 44 2 4 +1 Return + +1 FunctionEnd + +; RUN: llvm-spirv %s -to-binary -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.bc +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-LLVM: br label %{{[0-9]+}}, !llvm.loop ![[MD:[0-9]+]] +; CHECK-LLVM: ![[MD]] = distinct !{![[MD]], ![[MD_unroll_disable:[0-9]+]]} ; CHECK-LLVM: ![[MD_unroll_disable]] = !{!"llvm.loop.unroll.disable"}
\ No newline at end of file diff --git a/test/OpLoopMergeNone.spt b/test/OpLoopMergeNone.spt index 95b4808..8566aa1 100644 --- a/test/OpLoopMergeNone.spt +++ b/test/OpLoopMergeNone.spt @@ -1,87 +1,87 @@ -119734787 65536 458752 45 0
-2 Capability Addresses
-2 Capability Linkage
-2 Capability Kernel
-2 Capability Int64
-3 MemoryModel 2 2
-12 EntryPoint 6 1 "loop_merge_branch_conditional_none"
-3 Source 3 102000
-3 Name 2 "res"
-3 Name 3 "in"
-3 Name 4 "rep"
-3 Name 5 "num"
-4 Decorate 6 FuncParamAttr 5
-2 DecorationGroup 6
-4 Decorate 7 BuiltIn 28
-3 Decorate 7 Constant
-11 Decorate 7 LinkageAttributes "__spirv_GlobalInvocationId" Import
-4 GroupDecorate 6 2 3
-4 TypeInt 8 64 0
-4 TypeInt 14 32 1
-5 Constant 8 11 32 0
-4 Constant 14 15 0
-4 Constant 14 16 1
-4 TypeVector 9 8 3
-4 TypePointer 10 0 9
-2 TypeBool 12
-2 TypeVoid 13
-4 TypePointer 17 5 14
-4 TypePointer 18 7 14
-7 TypeFunction 19 13 17 17 14 14
-4 Variable 10 7 0
-
-5 Function 13 1 0 19
-3 FunctionParameter 17 2
-3 FunctionParameter 17 3
-3 FunctionParameter 14 4
-3 FunctionParameter 14 5
-
-2 Label 20
-6 Load 9 21 7 2 0
-5 CompositeExtract 8 22 21 0
-5 ShiftLeftLogical 8 23 22 11
-5 ShiftRightArithmetic 8 24 23 11
-4 SConvert 14 25 24
-4 Variable 18 26 7
-4 Variable 18 27 7
-5 Store 26 15 2 4
-5 Store 27 15 2 4
-2 Branch 28
-
-2 Label 28
-4 Load 14 29 27
-5 SLessThan 12 30 29 4
-4 LoopMerge 31 32 0
-4 BranchConditional 30 33 31
-
-2 Label 33
-4 Load 14 34 27
-5 IMul 14 35 34 5
-5 IAdd 14 36 25 35
-5 InBoundsPtrAccessChain 17 37 3 36
-4 Load 14 38 37
-4 Load 14 39 26
-5 IAdd 14 40 39 38
-5 Store 26 40 2 4
-2 Branch 32
-
-2 Label 32
-4 Load 14 41 27
-5 IAdd 14 42 41 16
-3 Store 27 42
-2 Branch 28
-
-2 Label 31
-4 Load 14 43 26
-5 InBoundsPtrAccessChain 17 44 2 24
-5 Store 44 43 2 4
-1 Return
-
-1 FunctionEnd
-
-; RUN: llvm-spirv %s -to-binary -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.bc
-; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-LLVM: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !llvm.loop ![[MD:[0-9]+]]
+119734787 65536 458752 45 0 +2 Capability Addresses +2 Capability Linkage +2 Capability Kernel +2 Capability Int64 +3 MemoryModel 2 2 +12 EntryPoint 6 1 "loop_merge_branch_conditional_none" +3 Source 3 102000 +3 Name 2 "res" +3 Name 3 "in" +3 Name 4 "rep" +3 Name 5 "num" +4 Decorate 6 FuncParamAttr 5 +2 DecorationGroup 6 +4 Decorate 7 BuiltIn 28 +3 Decorate 7 Constant +11 Decorate 7 LinkageAttributes "__spirv_GlobalInvocationId" Import +4 GroupDecorate 6 2 3 +4 TypeInt 8 64 0 +4 TypeInt 14 32 1 +5 Constant 8 11 32 0 +4 Constant 14 15 0 +4 Constant 14 16 1 +4 TypeVector 9 8 3 +4 TypePointer 10 0 9 +2 TypeBool 12 +2 TypeVoid 13 +4 TypePointer 17 5 14 +4 TypePointer 18 7 14 +7 TypeFunction 19 13 17 17 14 14 +4 Variable 10 7 0 + +5 Function 13 1 0 19 +3 FunctionParameter 17 2 +3 FunctionParameter 17 3 +3 FunctionParameter 14 4 +3 FunctionParameter 14 5 + +2 Label 20 +6 Load 9 21 7 2 0 +5 CompositeExtract 8 22 21 0 +5 ShiftLeftLogical 8 23 22 11 +5 ShiftRightArithmetic 8 24 23 11 +4 SConvert 14 25 24 +4 Variable 18 26 7 +4 Variable 18 27 7 +5 Store 26 15 2 4 +5 Store 27 15 2 4 +2 Branch 28 + +2 Label 28 +4 Load 14 29 27 +5 SLessThan 12 30 29 4 +4 LoopMerge 31 32 0 +4 BranchConditional 30 33 31 + +2 Label 33 +4 Load 14 34 27 +5 IMul 14 35 34 5 +5 IAdd 14 36 25 35 +5 InBoundsPtrAccessChain 17 37 3 36 +4 Load 14 38 37 +4 Load 14 39 26 +5 IAdd 14 40 39 38 +5 Store 26 40 2 4 +2 Branch 32 + +2 Label 32 +4 Load 14 41 27 +5 IAdd 14 42 41 16 +3 Store 27 42 +2 Branch 28 + +2 Label 31 +4 Load 14 43 26 +5 InBoundsPtrAccessChain 17 44 2 24 +5 Store 44 43 2 4 +1 Return + +1 FunctionEnd + +; RUN: llvm-spirv %s -to-binary -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.bc +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-LLVM: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !llvm.loop ![[MD:[0-9]+]] ; CHECK-LLVM: ![[MD]] = distinct !{![[MD]]}
\ No newline at end of file diff --git a/test/OpLoopMergeUnroll.spt b/test/OpLoopMergeUnroll.spt index 7253b3e..ced3416 100644 --- a/test/OpLoopMergeUnroll.spt +++ b/test/OpLoopMergeUnroll.spt @@ -1,88 +1,88 @@ -119734787 65536 458752 45 0
-2 Capability Addresses
-2 Capability Linkage
-2 Capability Kernel
-2 Capability Int64
-3 MemoryModel 2 2
-13 EntryPoint 6 1 "loop_merge_branch_conditional_unroll"
-3 Source 3 102000
-3 Name 2 "res"
-3 Name 3 "in"
-3 Name 4 "rep"
-3 Name 5 "num"
-4 Decorate 6 FuncParamAttr 5
-2 DecorationGroup 6
-4 Decorate 7 BuiltIn 28
-3 Decorate 7 Constant
-11 Decorate 7 LinkageAttributes "__spirv_GlobalInvocationId" Import
-4 GroupDecorate 6 2 3
-4 TypeInt 8 64 0
-4 TypeInt 14 32 1
-5 Constant 8 11 32 0
-4 Constant 14 15 0
-4 Constant 14 16 1
-4 TypeVector 9 8 3
-4 TypePointer 10 0 9
-2 TypeBool 12
-2 TypeVoid 13
-4 TypePointer 17 5 14
-4 TypePointer 18 7 14
-7 TypeFunction 19 13 17 17 14 14
-4 Variable 10 7 0
-
-5 Function 13 1 0 19
-3 FunctionParameter 17 2
-3 FunctionParameter 17 3
-3 FunctionParameter 14 4
-3 FunctionParameter 14 5
-
-2 Label 20
-6 Load 9 21 7 2 0
-5 CompositeExtract 8 22 21 0
-5 ShiftLeftLogical 8 23 22 11
-5 ShiftRightArithmetic 8 24 23 11
-4 SConvert 14 25 24
-4 Variable 18 26 7
-4 Variable 18 27 7
-5 Store 26 15 2 4
-5 Store 27 15 2 4
-2 Branch 28
-
-2 Label 28
-4 Load 14 29 27
-5 SLessThan 12 30 29 4
-4 LoopMerge 31 32 1
-4 BranchConditional 30 33 31
-
-2 Label 33
-4 Load 14 34 27
-5 IMul 14 35 34 5
-5 IAdd 14 36 25 35
-5 InBoundsPtrAccessChain 17 37 3 36
-4 Load 14 38 37
-4 Load 14 39 26
-5 IAdd 14 40 39 38
-5 Store 26 40 2 4
-2 Branch 32
-
-2 Label 32
-4 Load 14 41 27
-5 IAdd 14 42 41 16
-3 Store 27 42
-2 Branch 28
-
-2 Label 31
-4 Load 14 43 26
-5 InBoundsPtrAccessChain 17 44 2 24
-5 Store 44 43 2 4
-1 Return
-
-1 FunctionEnd
-
-; RUN: llvm-spirv %s -to-binary -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.bc
-; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-LLVM: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !llvm.loop ![[MD:[0-9]+]]
-; CHECK-LLVM: ![[MD]] = distinct !{![[MD]], ![[MD_unroll:[0-9]+]]}
+119734787 65536 458752 45 0 +2 Capability Addresses +2 Capability Linkage +2 Capability Kernel +2 Capability Int64 +3 MemoryModel 2 2 +13 EntryPoint 6 1 "loop_merge_branch_conditional_unroll" +3 Source 3 102000 +3 Name 2 "res" +3 Name 3 "in" +3 Name 4 "rep" +3 Name 5 "num" +4 Decorate 6 FuncParamAttr 5 +2 DecorationGroup 6 +4 Decorate 7 BuiltIn 28 +3 Decorate 7 Constant +11 Decorate 7 LinkageAttributes "__spirv_GlobalInvocationId" Import +4 GroupDecorate 6 2 3 +4 TypeInt 8 64 0 +4 TypeInt 14 32 1 +5 Constant 8 11 32 0 +4 Constant 14 15 0 +4 Constant 14 16 1 +4 TypeVector 9 8 3 +4 TypePointer 10 0 9 +2 TypeBool 12 +2 TypeVoid 13 +4 TypePointer 17 5 14 +4 TypePointer 18 7 14 +7 TypeFunction 19 13 17 17 14 14 +4 Variable 10 7 0 + +5 Function 13 1 0 19 +3 FunctionParameter 17 2 +3 FunctionParameter 17 3 +3 FunctionParameter 14 4 +3 FunctionParameter 14 5 + +2 Label 20 +6 Load 9 21 7 2 0 +5 CompositeExtract 8 22 21 0 +5 ShiftLeftLogical 8 23 22 11 +5 ShiftRightArithmetic 8 24 23 11 +4 SConvert 14 25 24 +4 Variable 18 26 7 +4 Variable 18 27 7 +5 Store 26 15 2 4 +5 Store 27 15 2 4 +2 Branch 28 + +2 Label 28 +4 Load 14 29 27 +5 SLessThan 12 30 29 4 +4 LoopMerge 31 32 1 +4 BranchConditional 30 33 31 + +2 Label 33 +4 Load 14 34 27 +5 IMul 14 35 34 5 +5 IAdd 14 36 25 35 +5 InBoundsPtrAccessChain 17 37 3 36 +4 Load 14 38 37 +4 Load 14 39 26 +5 IAdd 14 40 39 38 +5 Store 26 40 2 4 +2 Branch 32 + +2 Label 32 +4 Load 14 41 27 +5 IAdd 14 42 41 16 +3 Store 27 42 +2 Branch 28 + +2 Label 31 +4 Load 14 43 26 +5 InBoundsPtrAccessChain 17 44 2 24 +5 Store 44 43 2 4 +1 Return + +1 FunctionEnd + +; RUN: llvm-spirv %s -to-binary -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.bc +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-LLVM: br i1 %{{[0-9]+}}, label %{{[0-9]+}}, label %{{[0-9]+}}, !llvm.loop ![[MD:[0-9]+]] +; CHECK-LLVM: ![[MD]] = distinct !{![[MD]], ![[MD_unroll:[0-9]+]]} ; CHECK-LLVM: ![[MD_unroll]] = !{!"llvm.loop.unroll.full"}
\ No newline at end of file diff --git a/test/PipeStorage.ll b/test/PipeStorage.ll index 1fa0d93..7a5b5d4 100644 --- a/test/PipeStorage.ll +++ b/test/PipeStorage.ll @@ -1,58 +1,58 @@ -; RUN: llvm-as %s -o %t.bc
-; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt
-; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV
-; RUN: llvm-spirv %t.bc -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
-; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-LLVM: %spirv.ConstantPipeStorage = type { i32, i32, i32 }
-; CHECK-LLVM: %"[[CL_PIPE_STORAGE_NAME:[^"]+]]" = type { %spirv.PipeStorage addrspace(1)* }
-; CHECK-LLVM: %spirv.PipeStorage = type opaque
-; CHECK-LLVM: [[CREATOR_NAME:[^ ]+]] = linkonce_odr addrspace(1) global %spirv.ConstantPipeStorage { i32 16, i32 16, i32 1 }, align 4
-; CHECK-LLVM: @mygpipe = addrspace(1) global %"[[CL_PIPE_STORAGE_NAME]]" { %spirv.PipeStorage addrspace(1)* bitcast (%spirv.ConstantPipeStorage addrspace(1)* [[CREATOR_NAME]] to %spirv.PipeStorage addrspace(1)*) }, align 4
-
-; check for magic number followed by version 1.1
-; CHECK-SPIRV: 119734787 65792
-
-; CHECK-SPIRV: 4 Name [[MYPIPE_ID:[0-9]+]] "mygpipe"
-
-; CHECK-SPIRV: 2 TypePipeStorage [[PIPE_STORAGE_ID:[0-9]+]]
-; CHECK-SPIRV-NEXT: 2 TypePipeStorage [[PIPE_STORAGE_ID_2:[0-9]+]]
-; CHECK-SPIRV: 3 TypeStruct [[CL_PIPE_STORAGE_ID:[0-9]+]] [[PIPE_STORAGE_ID_2]]
-; CHECK-SPIRV: 4 TypePointer [[CL_PIPE_STORAGE_PTR_ID:[0-9]+]] 5 [[CL_PIPE_STORAGE_ID]]
-
-; CHECK-SPIRV: 6 ConstantPipeStorage [[PIPE_STORAGE_ID]] [[CPS_ID:[0-9]+]] 16 16 1
-; CHECK-SPIRV: 4 ConstantComposite [[CL_PIPE_STORAGE_ID]] [[COMPOSITE_ID:[0-9]+]] [[CPS_ID]]
-; CHECK-SPIRV: 5 Variable [[CL_PIPE_STORAGE_PTR_ID]] [[MYPIPE_ID]] 5 [[COMPOSITE_ID]]
-
-target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir-unknown-unknown"
-
-%spirv.ConstantPipeStorage = type { i32, i32, i32 }
-%"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" = type { %spirv.PipeStorage addrspace(1)* }
-%spirv.PipeStorage = type opaque
-
-@_ZN2cl9__details29OpConstantPipeStorage_CreatorILi16ELi16ELi1EE5valueE = linkonce_odr addrspace(1) global %spirv.ConstantPipeStorage { i32 16, i32 16, i32 1 }, align 4
-@mygpipe = addrspace(1) global %"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" { %spirv.PipeStorage addrspace(1)* bitcast (%spirv.ConstantPipeStorage addrspace(1)* @_ZN2cl9__details29OpConstantPipeStorage_CreatorILi16ELi16ELi1EE5valueE to %spirv.PipeStorage addrspace(1)*) }, align 4
-
-; Function Attrs: nounwind
-define spir_kernel void @worker() {
-entry:
- ret void
-}
-
-!opencl.enable.FP_CONTRACT = !{}
-!opencl.spir.version = !{!0}
-!opencl.ocl.version = !{!1}
-!opencl.used.extensions = !{!2}
-!opencl.used.optional.core.features = !{!2}
-!opencl.compiler.options = !{!2}
-!llvm.ident = !{!3}
-!spirv.Source = !{!4}
-!spirv.String = !{}
-
-!0 = !{i32 1, i32 2}
-!1 = !{i32 2, i32 2}
-!2 = !{}
-!3 = !{!"clang version 3.6.1 "}
-!4 = !{i32 4, i32 202000}
+; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt +; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-LLVM: %spirv.ConstantPipeStorage = type { i32, i32, i32 } +; CHECK-LLVM: %"[[CL_PIPE_STORAGE_NAME:[^"]+]]" = type { %spirv.PipeStorage addrspace(1)* } +; CHECK-LLVM: %spirv.PipeStorage = type opaque +; CHECK-LLVM: [[CREATOR_NAME:[^ ]+]] = linkonce_odr addrspace(1) global %spirv.ConstantPipeStorage { i32 16, i32 16, i32 1 }, align 4 +; CHECK-LLVM: @mygpipe = addrspace(1) global %"[[CL_PIPE_STORAGE_NAME]]" { %spirv.PipeStorage addrspace(1)* bitcast (%spirv.ConstantPipeStorage addrspace(1)* [[CREATOR_NAME]] to %spirv.PipeStorage addrspace(1)*) }, align 4 + +; check for magic number followed by version 1.1 +; CHECK-SPIRV: 119734787 65792 + +; CHECK-SPIRV: 4 Name [[MYPIPE_ID:[0-9]+]] "mygpipe" + +; CHECK-SPIRV: 2 TypePipeStorage [[PIPE_STORAGE_ID:[0-9]+]] +; CHECK-SPIRV-NEXT: 2 TypePipeStorage [[PIPE_STORAGE_ID_2:[0-9]+]] +; CHECK-SPIRV: 3 TypeStruct [[CL_PIPE_STORAGE_ID:[0-9]+]] [[PIPE_STORAGE_ID_2]] +; CHECK-SPIRV: 4 TypePointer [[CL_PIPE_STORAGE_PTR_ID:[0-9]+]] 5 [[CL_PIPE_STORAGE_ID]] + +; CHECK-SPIRV: 6 ConstantPipeStorage [[PIPE_STORAGE_ID]] [[CPS_ID:[0-9]+]] 16 16 1 +; CHECK-SPIRV: 4 ConstantComposite [[CL_PIPE_STORAGE_ID]] [[COMPOSITE_ID:[0-9]+]] [[CPS_ID]] +; CHECK-SPIRV: 5 Variable [[CL_PIPE_STORAGE_PTR_ID]] [[MYPIPE_ID]] 5 [[COMPOSITE_ID]] + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir-unknown-unknown" + +%spirv.ConstantPipeStorage = type { i32, i32, i32 } +%"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" = type { %spirv.PipeStorage addrspace(1)* } +%spirv.PipeStorage = type opaque + +@_ZN2cl9__details29OpConstantPipeStorage_CreatorILi16ELi16ELi1EE5valueE = linkonce_odr addrspace(1) global %spirv.ConstantPipeStorage { i32 16, i32 16, i32 1 }, align 4 +@mygpipe = addrspace(1) global %"class.cl::pipe_storage<int __attribute__((ext_vector_type(4))), 1>" { %spirv.PipeStorage addrspace(1)* bitcast (%spirv.ConstantPipeStorage addrspace(1)* @_ZN2cl9__details29OpConstantPipeStorage_CreatorILi16ELi16ELi1EE5valueE to %spirv.PipeStorage addrspace(1)*) }, align 4 + +; Function Attrs: nounwind +define spir_kernel void @worker() { +entry: + ret void +} + +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!0} +!opencl.ocl.version = !{!1} +!opencl.used.extensions = !{!2} +!opencl.used.optional.core.features = !{!2} +!opencl.compiler.options = !{!2} +!llvm.ident = !{!3} +!spirv.Source = !{!4} +!spirv.String = !{} + +!0 = !{i32 1, i32 2} +!1 = !{i32 2, i32 2} +!2 = !{} +!3 = !{!"clang version 3.6.1 "} +!4 = !{i32 4, i32 202000} diff --git a/test/SPIRVVersionAutodetect_1_0.ll b/test/SPIRVVersionAutodetect_1_0.ll index f0ed8ed..8508b97 100644 --- a/test/SPIRVVersionAutodetect_1_0.ll +++ b/test/SPIRVVersionAutodetect_1_0.ll @@ -1,31 +1,31 @@ -; RUN: llvm-as < %s | llvm-spirv -spirv-text -o %t
-; RUN: FileCheck < %t %s
-
-; check for magic number followed by version 1.0
-; CHECK: 119734787 65536
-
-target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir-unknown-unknown"
-
-; Function Attrs: nounwind
-define spir_kernel void @worker() #0 {
-entry:
- ret void
-}
-
-attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-
-!opencl.enable.FP_CONTRACT = !{}
-!opencl.spir.version = !{!6}
-!opencl.ocl.version = !{!7}
-!opencl.used.extensions = !{!8}
-!opencl.used.optional.core.features = !{!8}
-!opencl.compiler.options = !{!8}
-!llvm.ident = !{!9}
-!spirv.Source = !{!10}
-
-!6 = !{i32 1, i32 2}
-!7 = !{i32 2, i32 2}
-!8 = !{}
-!9 = !{!"clang version 3.6.1 "}
-!10 = !{i32 4, i32 202000}
+; RUN: llvm-as < %s | llvm-spirv -spirv-text -o %t +; RUN: FileCheck < %t %s + +; check for magic number followed by version 1.0 +; CHECK: 119734787 65536 + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir-unknown-unknown" + +; Function Attrs: nounwind +define spir_kernel void @worker() #0 { +entry: + ret void +} + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!6} +!opencl.ocl.version = !{!7} +!opencl.used.extensions = !{!8} +!opencl.used.optional.core.features = !{!8} +!opencl.compiler.options = !{!8} +!llvm.ident = !{!9} +!spirv.Source = !{!10} + +!6 = !{i32 1, i32 2} +!7 = !{i32 2, i32 2} +!8 = !{} +!9 = !{!"clang version 3.6.1 "} +!10 = !{i32 4, i32 202000} diff --git a/test/SPIRVVersionAutodetect_1_1.ll b/test/SPIRVVersionAutodetect_1_1.ll index 96751cf..43ca3fa 100644 --- a/test/SPIRVVersionAutodetect_1_1.ll +++ b/test/SPIRVVersionAutodetect_1_1.ll @@ -1,33 +1,33 @@ -; RUN: llvm-as < %s | llvm-spirv -spirv-text -o %t
-; RUN: FileCheck < %t %s
-
-; check for magic number followed by version 1.1
-; CHECK: 119734787 65792
-
-target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir-unknown-unknown"
-
-; Function Attrs: nounwind
-define spir_kernel void @worker() #0 {
-entry:
- ret void
-}
-
-attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-
-!spirv.ExecutionMode = !{!0}
-!opencl.enable.FP_CONTRACT = !{}
-!opencl.spir.version = !{!6}
-!opencl.ocl.version = !{!7}
-!opencl.used.extensions = !{!8}
-!opencl.used.optional.core.features = !{!8}
-!opencl.compiler.options = !{!8}
-!llvm.ident = !{!9}
-!spirv.Source = !{!10}
-
-!0 = !{void ()* @worker, i32 33}
-!6 = !{i32 1, i32 2}
-!7 = !{i32 2, i32 2}
-!8 = !{}
-!9 = !{!"clang version 3.6.1 "}
-!10 = !{i32 4, i32 202000}
+; RUN: llvm-as < %s | llvm-spirv -spirv-text -o %t +; RUN: FileCheck < %t %s + +; check for magic number followed by version 1.1 +; CHECK: 119734787 65792 + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir-unknown-unknown" + +; Function Attrs: nounwind +define spir_kernel void @worker() #0 { +entry: + ret void +} + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!spirv.ExecutionMode = !{!0} +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!6} +!opencl.ocl.version = !{!7} +!opencl.used.extensions = !{!8} +!opencl.used.optional.core.features = !{!8} +!opencl.compiler.options = !{!8} +!llvm.ident = !{!9} +!spirv.Source = !{!10} + +!0 = !{void ()* @worker, i32 33} +!6 = !{i32 1, i32 2} +!7 = !{i32 2, i32 2} +!8 = !{} +!9 = !{!"clang version 3.6.1 "} +!10 = !{i32 4, i32 202000} diff --git a/test/builtin_vars-decorate.ll b/test/builtin_vars-decorate.ll index 39d6653..d3ede33 100644 --- a/test/builtin_vars-decorate.ll +++ b/test/builtin_vars-decorate.ll @@ -1,96 +1,96 @@ -; RUN: llvm-as < %s | llvm-spirv -spirv-text -o %t
-; RUN: FileCheck < %t %s
-
-; ModuleID = 'test.cl'
-target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir-unknown-unknown"
-
-; CHECK: {{[0-9]+}} Name [[WD:[0-9]+]] "__spirv_BuiltInWorkDim"
-; CHECK: {{[0-9]+}} Name [[GS:[0-9]+]] "__spirv_BuiltInGlobalSize"
-; CHECK: {{[0-9]+}} Name [[GII:[0-9]+]] "__spirv_BuiltInGlobalInvocationId"
-; CHECK: {{[0-9]+}} Name [[WS:[0-9]+]] "__spirv_BuiltInWorkgroupSize"
-; CHECK: {{[0-9]+}} Name [[EWS:[0-9]+]] "__spirv_BuiltInEnqueuedWorkgroupSize"
-; CHECK: {{[0-9]+}} Name [[LLI:[0-9]+]] "__spirv_BuiltInLocalInvocationId"
-; CHECK: {{[0-9]+}} Name [[NW:[0-9]+]] "__spirv_BuiltInNumWorkgroups"
-; CHECK: {{[0-9]+}} Name [[WI:[0-9]+]] "__spirv_BuiltInWorkgroupId"
-; CHECK: {{[0-9]+}} Name [[GO:[0-9]+]] "__spirv_BuiltInGlobalOffset"
-; CHECK: {{[0-9]+}} Name [[GLI:[0-9]+]] "__spirv_BuiltInGlobalLinearId"
-; CHECK: {{[0-9]+}} Name [[LLII:[0-9]+]] "__spirv_BuiltInLocalInvocationIndex"
-; CHECK: {{[0-9]+}} Name [[SS:[0-9]+]] "__spirv_BuiltInSubgroupSize"
-; CHECK: {{[0-9]+}} Name [[SMS:[0-9]+]] "__spirv_BuiltInSubgroupMaxSize"
-; CHECK: {{[0-9]+}} Name [[NS:[0-9]+]] "__spirv_BuiltInNumSubgroups"
-; CHECK: {{[0-9]+}} Name [[NES:[0-9]+]] "__spirv_BuiltInNumEnqueuedSubgroups"
-; CHECK: {{[0-9]+}} Name [[SI:[0-9]+]] "__spirv_BuiltInSubgroupId"
-; CHECK: {{[0-9]+}} Name [[SLII:[0-9]+]] "__spirv_BuiltInSubgroupLocalInvocationId"
-
-; CHECK: 4 Decorate [[NW]] BuiltIn 24
-; CHECK: 4 Decorate [[WS]] BuiltIn 25
-; CHECK: 4 Decorate [[WI]] BuiltIn 26
-; CHECK: 4 Decorate [[LLI]] BuiltIn 27
-; CHECK: 4 Decorate [[GII]] BuiltIn 28
-; CHECK: 4 Decorate [[LLII]] BuiltIn 29
-; CHECK: 4 Decorate [[WD]] BuiltIn 30
-; CHECK: 4 Decorate [[GS]] BuiltIn 31
-; CHECK: 4 Decorate [[EWS]] BuiltIn 32
-; CHECK: 4 Decorate [[GO]] BuiltIn 33
-; CHECK: 4 Decorate [[GLI]] BuiltIn 34
-; CHECK: 4 Decorate [[SS]] BuiltIn 36
-; CHECK: 4 Decorate [[SMS]] BuiltIn 37
-; CHECK: 4 Decorate [[NS]] BuiltIn 38
-; CHECK: 4 Decorate [[NES]] BuiltIn 39
-; CHECK: 4 Decorate [[SI]] BuiltIn 40
-; CHECK: 4 Decorate [[SLII]] BuiltIn 41
-@__spirv_BuiltInWorkDim = external addrspace(1) global i32
-@__spirv_BuiltInGlobalSize = external addrspace(1) global <3 x i32>
-@__spirv_BuiltInGlobalInvocationId = external addrspace(1) global <3 x i32>
-@__spirv_BuiltInWorkgroupSize = external addrspace(1) global <3 x i32>
-@__spirv_BuiltInEnqueuedWorkgroupSize = external addrspace(1) global <3 x i32>
-@__spirv_BuiltInLocalInvocationId = external addrspace(1) global <3 x i32>
-@__spirv_BuiltInNumWorkgroups = external addrspace(1) global <3 x i32>
-@__spirv_BuiltInWorkgroupId = external addrspace(1) global <3 x i32>
-@__spirv_BuiltInGlobalOffset = external addrspace(1) global <3 x i32>
-@__spirv_BuiltInGlobalLinearId = external addrspace(1) global i32
-@__spirv_BuiltInLocalInvocationIndex = external addrspace(1) global i32
-@__spirv_BuiltInSubgroupSize = external addrspace(1) global i32
-@__spirv_BuiltInSubgroupMaxSize = external addrspace(1) global i32
-@__spirv_BuiltInNumSubgroups = external addrspace(1) global i32
-@__spirv_BuiltInNumEnqueuedSubgroups = external addrspace(1) global i32
-@__spirv_BuiltInSubgroupId = external addrspace(1) global i32
-@__spirv_BuiltInSubgroupLocalInvocationId = external addrspace(1) global i32
-
-; Function Attrs: nounwind readnone
-define spir_kernel void @_Z1wv() #1 {
-entry:
- ret void
-}
-
-attributes #0 = { alwaysinline nounwind readonly "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #1 = { nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-
-!opencl.kernels = !{!0}
-!opencl.enable.FP_CONTRACT = !{}
-!opencl.spir.version = !{!6}
-!opencl.ocl.version = !{!7}
-!opencl.used.extensions = !{!8}
-!opencl.used.optional.core.features = !{!8}
-!opencl.compiler.options = !{!8}
-!llvm.ident = !{!9}
-!spirv.Source = !{!10}
-!spirv.String = !{!11}
-
-!0 = !{void ()* @_Z1wv, !1, !2, !3, !4, !5}
-!1 = !{!"kernel_arg_addr_space"}
-!2 = !{!"kernel_arg_access_qual"}
-!3 = !{!"kernel_arg_type"}
-!4 = !{!"kernel_arg_base_type"}
-!5 = !{!"kernel_arg_type_qual"}
-!6 = !{i32 1, i32 2}
-!7 = !{i32 2, i32 1}
-!8 = !{}
-!9 = !{!"clang version 3.6.1 "}
-!10 = !{i32 3, i32 200000, !11}
-!11 = !{!"test.cl"}
-!12 = !{!13, !13, i64 0}
-!13 = !{!"int", !14, i64 0}
-!14 = !{!"omnipotent char", !15, i64 0}
-!15 = !{!"Simple C/C++ TBAA"}
+; RUN: llvm-as < %s | llvm-spirv -spirv-text -o %t +; RUN: FileCheck < %t %s + +; ModuleID = 'test.cl' +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir-unknown-unknown" + +; CHECK: {{[0-9]+}} Name [[WD:[0-9]+]] "__spirv_BuiltInWorkDim" +; CHECK: {{[0-9]+}} Name [[GS:[0-9]+]] "__spirv_BuiltInGlobalSize" +; CHECK: {{[0-9]+}} Name [[GII:[0-9]+]] "__spirv_BuiltInGlobalInvocationId" +; CHECK: {{[0-9]+}} Name [[WS:[0-9]+]] "__spirv_BuiltInWorkgroupSize" +; CHECK: {{[0-9]+}} Name [[EWS:[0-9]+]] "__spirv_BuiltInEnqueuedWorkgroupSize" +; CHECK: {{[0-9]+}} Name [[LLI:[0-9]+]] "__spirv_BuiltInLocalInvocationId" +; CHECK: {{[0-9]+}} Name [[NW:[0-9]+]] "__spirv_BuiltInNumWorkgroups" +; CHECK: {{[0-9]+}} Name [[WI:[0-9]+]] "__spirv_BuiltInWorkgroupId" +; CHECK: {{[0-9]+}} Name [[GO:[0-9]+]] "__spirv_BuiltInGlobalOffset" +; CHECK: {{[0-9]+}} Name [[GLI:[0-9]+]] "__spirv_BuiltInGlobalLinearId" +; CHECK: {{[0-9]+}} Name [[LLII:[0-9]+]] "__spirv_BuiltInLocalInvocationIndex" +; CHECK: {{[0-9]+}} Name [[SS:[0-9]+]] "__spirv_BuiltInSubgroupSize" +; CHECK: {{[0-9]+}} Name [[SMS:[0-9]+]] "__spirv_BuiltInSubgroupMaxSize" +; CHECK: {{[0-9]+}} Name [[NS:[0-9]+]] "__spirv_BuiltInNumSubgroups" +; CHECK: {{[0-9]+}} Name [[NES:[0-9]+]] "__spirv_BuiltInNumEnqueuedSubgroups" +; CHECK: {{[0-9]+}} Name [[SI:[0-9]+]] "__spirv_BuiltInSubgroupId" +; CHECK: {{[0-9]+}} Name [[SLII:[0-9]+]] "__spirv_BuiltInSubgroupLocalInvocationId" + +; CHECK: 4 Decorate [[NW]] BuiltIn 24 +; CHECK: 4 Decorate [[WS]] BuiltIn 25 +; CHECK: 4 Decorate [[WI]] BuiltIn 26 +; CHECK: 4 Decorate [[LLI]] BuiltIn 27 +; CHECK: 4 Decorate [[GII]] BuiltIn 28 +; CHECK: 4 Decorate [[LLII]] BuiltIn 29 +; CHECK: 4 Decorate [[WD]] BuiltIn 30 +; CHECK: 4 Decorate [[GS]] BuiltIn 31 +; CHECK: 4 Decorate [[EWS]] BuiltIn 32 +; CHECK: 4 Decorate [[GO]] BuiltIn 33 +; CHECK: 4 Decorate [[GLI]] BuiltIn 34 +; CHECK: 4 Decorate [[SS]] BuiltIn 36 +; CHECK: 4 Decorate [[SMS]] BuiltIn 37 +; CHECK: 4 Decorate [[NS]] BuiltIn 38 +; CHECK: 4 Decorate [[NES]] BuiltIn 39 +; CHECK: 4 Decorate [[SI]] BuiltIn 40 +; CHECK: 4 Decorate [[SLII]] BuiltIn 41 +@__spirv_BuiltInWorkDim = external addrspace(1) global i32 +@__spirv_BuiltInGlobalSize = external addrspace(1) global <3 x i32> +@__spirv_BuiltInGlobalInvocationId = external addrspace(1) global <3 x i32> +@__spirv_BuiltInWorkgroupSize = external addrspace(1) global <3 x i32> +@__spirv_BuiltInEnqueuedWorkgroupSize = external addrspace(1) global <3 x i32> +@__spirv_BuiltInLocalInvocationId = external addrspace(1) global <3 x i32> +@__spirv_BuiltInNumWorkgroups = external addrspace(1) global <3 x i32> +@__spirv_BuiltInWorkgroupId = external addrspace(1) global <3 x i32> +@__spirv_BuiltInGlobalOffset = external addrspace(1) global <3 x i32> +@__spirv_BuiltInGlobalLinearId = external addrspace(1) global i32 +@__spirv_BuiltInLocalInvocationIndex = external addrspace(1) global i32 +@__spirv_BuiltInSubgroupSize = external addrspace(1) global i32 +@__spirv_BuiltInSubgroupMaxSize = external addrspace(1) global i32 +@__spirv_BuiltInNumSubgroups = external addrspace(1) global i32 +@__spirv_BuiltInNumEnqueuedSubgroups = external addrspace(1) global i32 +@__spirv_BuiltInSubgroupId = external addrspace(1) global i32 +@__spirv_BuiltInSubgroupLocalInvocationId = external addrspace(1) global i32 + +; Function Attrs: nounwind readnone +define spir_kernel void @_Z1wv() #1 { +entry: + ret void +} + +attributes #0 = { alwaysinline nounwind readonly "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!opencl.kernels = !{!0} +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!6} +!opencl.ocl.version = !{!7} +!opencl.used.extensions = !{!8} +!opencl.used.optional.core.features = !{!8} +!opencl.compiler.options = !{!8} +!llvm.ident = !{!9} +!spirv.Source = !{!10} +!spirv.String = !{!11} + +!0 = !{void ()* @_Z1wv, !1, !2, !3, !4, !5} +!1 = !{!"kernel_arg_addr_space"} +!2 = !{!"kernel_arg_access_qual"} +!3 = !{!"kernel_arg_type"} +!4 = !{!"kernel_arg_base_type"} +!5 = !{!"kernel_arg_type_qual"} +!6 = !{i32 1, i32 2} +!7 = !{i32 2, i32 1} +!8 = !{} +!9 = !{!"clang version 3.6.1 "} +!10 = !{i32 3, i32 200000, !11} +!11 = !{!"test.cl"} +!12 = !{!13, !13, i64 0} +!13 = !{!"int", !14, i64 0} +!14 = !{!"omnipotent char", !15, i64 0} +!15 = !{!"Simple C/C++ TBAA"} diff --git a/test/composite_construct_struct.spt b/test/composite_construct_struct.spt index a3c20c8..2e5b9de 100644 --- a/test/composite_construct_struct.spt +++ b/test/composite_construct_struct.spt @@ -1,56 +1,56 @@ -119734787 65536 458752 29 0
-2 Capability Addresses
-2 Capability Linkage
-2 Capability Kernel
-2 Capability Int64
-3 MemoryModel 2 2
-10 EntryPoint 6 1 "composite_construct_struct"
-3 Source 3 102000
-3 Name 2 "in"
-4 Decorate 3 BuiltIn 28
-3 Decorate 3 Constant
-4 Decorate 2 FuncParamAttr 5
-11 Decorate 3 LinkageAttributes "__spirv_GlobalInvocationId" Import
-4 TypeInt 4 64 0
-4 TypeInt 8 32 1
-4 TypeInt 10 8 1
-5 Constant 4 15 32 0
-4 Constant 8 16 2194483696
-4 Constant 10 17 4294967168
-4 Constant 8 18 2194487296
-4 Constant 8 19 2100480000
-4 TypeVector 5 4 3
-4 TypePointer 6 0 5
-2 TypeVoid 7
-4 TypeVector 9 8 2
-4 TypeStruct 11 8 10
-4 TypeStruct 12 9 11
-4 TypePointer 13 5 12
-4 TypeFunction 14 7 13
-5 ConstantComposite 9 20 18 19
-4 Variable 6 3 0
-
-5 Function 7 1 0 14
-3 FunctionParameter 13 2
-
-2 Label 21
-5 CompositeConstruct 11 22 16 17
-5 CompositeConstruct 12 23 20 22
-6 Load 5 24 3 2 0
-5 CompositeExtract 4 25 24 0
-5 ShiftLeftLogical 4 26 25 15
-5 ShiftRightArithmetic 4 27 26 15
-5 InBoundsPtrAccessChain 13 28 2 27
-3 Store 28 23
-1 Return
-
-1 FunctionEnd
-
-; RUN: llvm-spirv %s -to-binary -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.bc
-; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-LLVM: %[[struct0_type:[0-9]+]] = type { <2 x i32>, %[[struct1_type:[0-9]+]] }
-; CHECK-LLVM: %[[struct1_type]] = type { i32, i8 }
-; CHECK-LLVM: %[[struct:[0-9]+]] = getelementptr inbounds %[[struct0_type]], %[[struct0_type]] addrspace(1)* %in, i64 %{{[0-9]*}}
-; CHECK-LLVM: store %[[struct0_type]] { <2 x i32> <i32 -2100480000, i32 2100480000>, %[[struct1_type]] { i32 -2100483600, i8 -128 } }, %[[struct0_type]] addrspace(1)* %[[struct]]
+119734787 65536 458752 29 0 +2 Capability Addresses +2 Capability Linkage +2 Capability Kernel +2 Capability Int64 +3 MemoryModel 2 2 +10 EntryPoint 6 1 "composite_construct_struct" +3 Source 3 102000 +3 Name 2 "in" +4 Decorate 3 BuiltIn 28 +3 Decorate 3 Constant +4 Decorate 2 FuncParamAttr 5 +11 Decorate 3 LinkageAttributes "__spirv_GlobalInvocationId" Import +4 TypeInt 4 64 0 +4 TypeInt 8 32 1 +4 TypeInt 10 8 1 +5 Constant 4 15 32 0 +4 Constant 8 16 2194483696 +4 Constant 10 17 4294967168 +4 Constant 8 18 2194487296 +4 Constant 8 19 2100480000 +4 TypeVector 5 4 3 +4 TypePointer 6 0 5 +2 TypeVoid 7 +4 TypeVector 9 8 2 +4 TypeStruct 11 8 10 +4 TypeStruct 12 9 11 +4 TypePointer 13 5 12 +4 TypeFunction 14 7 13 +5 ConstantComposite 9 20 18 19 +4 Variable 6 3 0 + +5 Function 7 1 0 14 +3 FunctionParameter 13 2 + +2 Label 21 +5 CompositeConstruct 11 22 16 17 +5 CompositeConstruct 12 23 20 22 +6 Load 5 24 3 2 0 +5 CompositeExtract 4 25 24 0 +5 ShiftLeftLogical 4 26 25 15 +5 ShiftRightArithmetic 4 27 26 15 +5 InBoundsPtrAccessChain 13 28 2 27 +3 Store 28 23 +1 Return + +1 FunctionEnd + +; RUN: llvm-spirv %s -to-binary -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.bc +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-LLVM: %[[struct0_type:[0-9]+]] = type { <2 x i32>, %[[struct1_type:[0-9]+]] } +; CHECK-LLVM: %[[struct1_type]] = type { i32, i8 } +; CHECK-LLVM: %[[struct:[0-9]+]] = getelementptr inbounds %[[struct0_type]], %[[struct0_type]] addrspace(1)* %in, i64 %{{[0-9]*}} +; CHECK-LLVM: store %[[struct0_type]] { <2 x i32> <i32 -2100480000, i32 2100480000>, %[[struct1_type]] { i32 -2100483600, i8 -128 } }, %[[struct0_type]] addrspace(1)* %[[struct]] diff --git a/test/composite_construct_vector.spt b/test/composite_construct_vector.spt index d9456c7..071eb6c 100644 --- a/test/composite_construct_vector.spt +++ b/test/composite_construct_vector.spt @@ -1,49 +1,49 @@ -119734787 65536 458752 24 0
-2 Capability Addresses
-2 Capability Linkage
-2 Capability Kernel
-2 Capability Int64
-3 MemoryModel 2 2
-10 EntryPoint 6 1 "composite_construct_int4"
-3 Source 3 102000
-3 Name 2 "in"
-4 Decorate 3 BuiltIn 28
-3 Decorate 3 Constant
-4 Decorate 2 FuncParamAttr 5
-11 Decorate 3 LinkageAttributes "__spirv_GlobalInvocationId" Import
-4 TypeInt 4 64 0
-4 TypeInt 8 32 1
-5 Constant 4 12 32 0
-4 Constant 8 13 -123
-4 Constant 8 14 -122
-4 Constant 8 15 -121
-4 Constant 8 16 -119
-4 TypeVector 5 4 3
-4 TypePointer 6 0 5
-2 TypeVoid 7
-4 TypeVector 9 8 4
-4 TypePointer 10 5 9
-4 TypeFunction 11 7 10
-4 Variable 6 3 0
-
-5 Function 7 1 0 11
-3 FunctionParameter 10 2
-
-2 Label 17
-6 Load 5 18 3 2 0
-5 CompositeExtract 4 19 18 0
-5 ShiftLeftLogical 4 20 19 12
-5 ShiftRightArithmetic 4 21 20 12
-7 CompositeConstruct 9 22 13 14 15 16
-5 InBoundsPtrAccessChain 10 23 2 21
-3 Store 23 22
-1 Return
-
-1 FunctionEnd
-
-; RUN: llvm-spirv %s -to-binary -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.bc
-; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-LLVM: %[[vector:[0-9]+]] = getelementptr inbounds <4 x i32>, <4 x i32> addrspace(1)* %in, i64 %{{[0-9]*}}
-; CHECK-LLVM: store <4 x i32> <i32 -123, i32 -122, i32 -121, i32 -119>, <4 x i32> addrspace(1)* %[[vector]]
+119734787 65536 458752 24 0 +2 Capability Addresses +2 Capability Linkage +2 Capability Kernel +2 Capability Int64 +3 MemoryModel 2 2 +10 EntryPoint 6 1 "composite_construct_int4" +3 Source 3 102000 +3 Name 2 "in" +4 Decorate 3 BuiltIn 28 +3 Decorate 3 Constant +4 Decorate 2 FuncParamAttr 5 +11 Decorate 3 LinkageAttributes "__spirv_GlobalInvocationId" Import +4 TypeInt 4 64 0 +4 TypeInt 8 32 1 +5 Constant 4 12 32 0 +4 Constant 8 13 -123 +4 Constant 8 14 -122 +4 Constant 8 15 -121 +4 Constant 8 16 -119 +4 TypeVector 5 4 3 +4 TypePointer 6 0 5 +2 TypeVoid 7 +4 TypeVector 9 8 4 +4 TypePointer 10 5 9 +4 TypeFunction 11 7 10 +4 Variable 6 3 0 + +5 Function 7 1 0 11 +3 FunctionParameter 10 2 + +2 Label 17 +6 Load 5 18 3 2 0 +5 CompositeExtract 4 19 18 0 +5 ShiftLeftLogical 4 20 19 12 +5 ShiftRightArithmetic 4 21 20 12 +7 CompositeConstruct 9 22 13 14 15 16 +5 InBoundsPtrAccessChain 10 23 2 21 +3 Store 23 22 +1 Return + +1 FunctionEnd + +; RUN: llvm-spirv %s -to-binary -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.bc +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-LLVM: %[[vector:[0-9]+]] = getelementptr inbounds <4 x i32>, <4 x i32> addrspace(1)* %in, i64 %{{[0-9]*}} +; CHECK-LLVM: store <4 x i32> <i32 -123, i32 -122, i32 -121, i32 -119>, <4 x i32> addrspace(1)* %[[vector]] diff --git a/test/copy_object.spt b/test/copy_object.spt index 24b12c0..7be6f5d 100644 --- a/test/copy_object.spt +++ b/test/copy_object.spt @@ -1,50 +1,50 @@ -119734787 65536 458752 20 0
-2 Capability Addresses
-2 Capability Linkage
-2 Capability Kernel
-2 Capability Int64
-3 MemoryModel 2 2
-8 EntryPoint 6 1 "copy_object"
-3 Source 3 102000
-3 Name 2 "in"
-4 Decorate 3 BuiltIn 28
-3 Decorate 3 Constant
-4 Decorate 2 FuncParamAttr 5
-11 Decorate 3 LinkageAttributes "__spirv_GlobalInvocationId" Import
-4 TypeInt 4 64 0
-4 TypeInt 8 8 1
-5 Constant 4 11 32 0
-4 Constant 8 12 -20
-4 TypeVector 5 4 3
-4 TypePointer 6 0 5
-2 TypeVoid 7
-4 TypePointer 9 5 8
-4 TypeFunction 10 7 9
-4 Variable 6 3 0
-
-5 Function 7 1 0 10
-3 FunctionParameter 9 2
-
-2 Label 13
-6 Load 5 14 3 2 0
-5 CompositeExtract 4 15 14 0
-5 ShiftLeftLogical 4 16 15 11
-5 ShiftRightArithmetic 4 17 16 11
-5 InBoundsPtrAccessChain 9 18 2 17
-4 CopyObject 8 19 12
-3 Store 18 19
-1 Return
-
-1 FunctionEnd
-
-; FIXME: LIT comments/commands are moved at the end because llvm-spirv stops
-; reading the file after first ';' symbol
-
-; RUN: llvm-spirv %s -to-binary -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.bc
-; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-LLVM-NOT: CopyObject
-; CHECK-LLVM: %[[char:[0-9]+]] = alloca i8
-; CHECK-LLVM: store i8 -20, i8* %[[char]]
-; CHECK-LLVM: %{{[0-9]*}} = load i8, i8* %[[char]]
+119734787 65536 458752 20 0 +2 Capability Addresses +2 Capability Linkage +2 Capability Kernel +2 Capability Int64 +3 MemoryModel 2 2 +8 EntryPoint 6 1 "copy_object" +3 Source 3 102000 +3 Name 2 "in" +4 Decorate 3 BuiltIn 28 +3 Decorate 3 Constant +4 Decorate 2 FuncParamAttr 5 +11 Decorate 3 LinkageAttributes "__spirv_GlobalInvocationId" Import +4 TypeInt 4 64 0 +4 TypeInt 8 8 1 +5 Constant 4 11 32 0 +4 Constant 8 12 -20 +4 TypeVector 5 4 3 +4 TypePointer 6 0 5 +2 TypeVoid 7 +4 TypePointer 9 5 8 +4 TypeFunction 10 7 9 +4 Variable 6 3 0 + +5 Function 7 1 0 10 +3 FunctionParameter 9 2 + +2 Label 13 +6 Load 5 14 3 2 0 +5 CompositeExtract 4 15 14 0 +5 ShiftLeftLogical 4 16 15 11 +5 ShiftRightArithmetic 4 17 16 11 +5 InBoundsPtrAccessChain 9 18 2 17 +4 CopyObject 8 19 12 +3 Store 18 19 +1 Return + +1 FunctionEnd + +; FIXME: LIT comments/commands are moved at the end because llvm-spirv stops +; reading the file after first ';' symbol + +; RUN: llvm-spirv %s -to-binary -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.bc +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-LLVM-NOT: CopyObject +; CHECK-LLVM: %[[char:[0-9]+]] = alloca i8 +; CHECK-LLVM: store i8 -20, i8* %[[char]] +; CHECK-LLVM: %{{[0-9]*}} = load i8, i8* %[[char]] diff --git a/test/fmod.ll b/test/fmod.ll index a9af9a2..923cdca 100644 --- a/test/fmod.ll +++ b/test/fmod.ll @@ -1,50 +1,50 @@ -; __kernel void fmod_kernel( float out, float in1, float in2 )
-; { out = fmod( in1, in2 ); }
-
-; RUN: llvm-as %s -o %t.bc
-; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt
-; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
-; RUN: llvm-spirv %t.bc -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.bc
-; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-SPIRV: 7 ExtInst {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} fmod {{[0-9]+}} {{[0-9]+}}
-; CHECK-LLVM: call spir_func float @_Z4fmodff
-; CHECK-LLVM: declare spir_func float @_Z4fmodff(float, float)
-
-target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
-target triple = "spir64-unknown-unknown"
-
-; Function Attrs: nounwind
-define spir_kernel void @fmod_kernel(float %out, float %in1, float %in2) #0 {
-entry:
- %call = call spir_func float @_Z4fmodff(float %in1, float %in2) #2
- ret void
-}
-
-; Function Attrs: nounwind readnone
-declare spir_func float @_Z4fmodff(float, float) #1
-
-attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #1 = { nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #2 = { nounwind readnone }
-
-!opencl.kernels = !{!0}
-!opencl.enable.FP_CONTRACT = !{}
-!opencl.spir.version = !{!6}
-!opencl.ocl.version = !{!7}
-!opencl.used.extensions = !{!8}
-!opencl.used.optional.core.features = !{!8}
-!opencl.compiler.options = !{!8}
-!llvm.ident = !{!9}
-
-!0 = !{void (float, float, float)* @fmod_kernel, !1, !2, !3, !4, !5}
-!1 = !{!"kernel_arg_addr_space", i32 0, i32 0, i32 0}
-!2 = !{!"kernel_arg_access_qual", !"none", !"none", !"none"}
-!3 = !{!"kernel_arg_type", !"float", !"float", !"float"}
-!4 = !{!"kernel_arg_base_type", !"float", !"float", !"float"}
-!5 = !{!"kernel_arg_type_qual", !"", !"", !""}
-!6 = !{i32 1, i32 2}
-!7 = !{i32 2, i32 0}
-!8 = !{}
+; __kernel void fmod_kernel( float out, float in1, float in2 ) +; { out = fmod( in1, in2 ); } + +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt +; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.bc +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-SPIRV: 7 ExtInst {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} fmod {{[0-9]+}} {{[0-9]+}} +; CHECK-LLVM: call spir_func float @_Z4fmodff +; CHECK-LLVM: declare spir_func float @_Z4fmodff(float, float) + +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64" +target triple = "spir64-unknown-unknown" + +; Function Attrs: nounwind +define spir_kernel void @fmod_kernel(float %out, float %in1, float %in2) #0 { +entry: + %call = call spir_func float @_Z4fmodff(float %in1, float %in2) #2 + ret void +} + +; Function Attrs: nounwind readnone +declare spir_func float @_Z4fmodff(float, float) #1 + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } + +!opencl.kernels = !{!0} +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!6} +!opencl.ocl.version = !{!7} +!opencl.used.extensions = !{!8} +!opencl.used.optional.core.features = !{!8} +!opencl.compiler.options = !{!8} +!llvm.ident = !{!9} + +!0 = !{void (float, float, float)* @fmod_kernel, !1, !2, !3, !4, !5} +!1 = !{!"kernel_arg_addr_space", i32 0, i32 0, i32 0} +!2 = !{!"kernel_arg_access_qual", !"none", !"none", !"none"} +!3 = !{!"kernel_arg_type", !"float", !"float", !"float"} +!4 = !{!"kernel_arg_base_type", !"float", !"float", !"float"} +!5 = !{!"kernel_arg_type_qual", !"", !"", !""} +!6 = !{i32 1, i32 2} +!7 = !{i32 2, i32 0} +!8 = !{} !9 = !{!"clang version 3.6.1"}
\ No newline at end of file diff --git a/test/lifetime.ll b/test/lifetime.ll index a54c039..95dec7b 100644 --- a/test/lifetime.ll +++ b/test/lifetime.ll @@ -1,73 +1,73 @@ -; RUN: llvm-as %s -o %t.bc
-; RUN: llvm-spirv %t.bc -spirv-mem2reg=0 -o %t.spv
-; RUN: llvm-spirv %t.spv -to-text -o %t.spt
-; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
-; RUN: llvm-spirv -r %t.spv -o %t.spv.bc
-; RUN: llvm-dis < %t.spv.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-SPIRV-NOT: Bitcast
-; CHECK-SPIRV: 3 LifetimeStart [[tmp:[0-9]+]] 0
-; CHECK-SPIRV: 3 LifetimeStop [[tmp]] 0
-
-; CHECK-LLVM: %[[tmp1:[0-9]+]] = bitcast i32* %{{[0-9]+}} to i8*
-; CHECK-LLVM: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %[[tmp1]])
-; CHECK-LLVM: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %[[tmp1]])
-; CHECK-LLVM: declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
-; CHECK-LLVM: declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)
-
-; ModuleID = 'main'
-target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir64-unknown-unknown"
-
-; Function Attrs: nounwind
-define spir_kernel void @lifetime_simple(i32 addrspace(1)* nocapture %res, i32 addrspace(1)* nocapture %lhs, i32 addrspace(1)* nocapture %rhs) #0 {
- %1 = alloca i32
- %2 = call spir_func i64 @_Z13get_global_idj(i32 0) #1
- %3 = shl i64 %2, 32
- %4 = ashr exact i64 %3, 32
- %5 = getelementptr inbounds i32, i32 addrspace(1)* %lhs, i64 %4
- %6 = load i32, i32 addrspace(1)* %5, align 4
- %7 = getelementptr inbounds i32, i32 addrspace(1)* %rhs, i64 %4
- %8 = load i32, i32 addrspace(1)* %7, align 4
- %9 = sub i32 %6, %8
- %10 = bitcast i32* %1 to i8*
- call void @llvm.lifetime.start.p0i8(i64 -1, i8* %10)
- store i32 %9, i32* %1
- %11 = load i32, i32* %1
- call void @llvm.lifetime.end.p0i8(i64 -1, i8* %10)
- %12 = getelementptr inbounds i32, i32 addrspace(1)* %res, i64 %4
- store i32 %11, i32 addrspace(1)* %12, align 4
- ret void
-}
-
-; Function Attrs: nounwind
-declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #0
-
-; Function Attrs: nounwind
-declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #0
-
-; Function Attrs: nounwind readnone
-declare spir_func i64 @_Z13get_global_idj(i32) #1
-
-attributes #0 = { nounwind }
-attributes #1 = { nounwind readnone }
-
-!opencl.kernels = !{!0}
-!opencl.enable.FP_CONTRACT = !{}
-!spirv.Source = !{!6}
-!opencl.spir.version = !{!7}
-!opencl.ocl.version = !{!7}
-!opencl.used.extensions = !{!8}
-!opencl.used.optional.core.features = !{!8}
-!spirv.Generator = !{!9}
-
-!0 = !{void (i32 addrspace(1)*, i32 addrspace(1)*, i32 addrspace(1)*)* @lifetime_simple, !1, !2, !3, !4, !5}
-!1 = !{!"kernel_arg_addr_space", i32 1, i32 1, i32 1}
-!2 = !{!"kernel_arg_access_qual", !"none", !"none", !"none"}
-!3 = !{!"kernel_arg_type", !"int*", !"int*", !"int*"}
-!4 = !{!"kernel_arg_type_qual", !"", !"", !""}
-!5 = !{!"kernel_arg_base_type", !"int*", !"int*", !"int*"}
-!6 = !{i32 3, i32 102000}
-!7 = !{i32 1, i32 2}
-!8 = !{}
-!9 = !{i16 7, i16 0}
+; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-mem2reg=0 -o %t.spv +; RUN: llvm-spirv %t.spv -to-text -o %t.spt +; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv -r %t.spv -o %t.spv.bc +; RUN: llvm-dis < %t.spv.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-SPIRV-NOT: Bitcast +; CHECK-SPIRV: 3 LifetimeStart [[tmp:[0-9]+]] 0 +; CHECK-SPIRV: 3 LifetimeStop [[tmp]] 0 + +; CHECK-LLVM: %[[tmp1:[0-9]+]] = bitcast i32* %{{[0-9]+}} to i8* +; CHECK-LLVM: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %[[tmp1]]) +; CHECK-LLVM: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %[[tmp1]]) +; CHECK-LLVM: declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) +; CHECK-LLVM: declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) + +; ModuleID = 'main' +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir64-unknown-unknown" + +; Function Attrs: nounwind +define spir_kernel void @lifetime_simple(i32 addrspace(1)* nocapture %res, i32 addrspace(1)* nocapture %lhs, i32 addrspace(1)* nocapture %rhs) #0 { + %1 = alloca i32 + %2 = call spir_func i64 @_Z13get_global_idj(i32 0) #1 + %3 = shl i64 %2, 32 + %4 = ashr exact i64 %3, 32 + %5 = getelementptr inbounds i32, i32 addrspace(1)* %lhs, i64 %4 + %6 = load i32, i32 addrspace(1)* %5, align 4 + %7 = getelementptr inbounds i32, i32 addrspace(1)* %rhs, i64 %4 + %8 = load i32, i32 addrspace(1)* %7, align 4 + %9 = sub i32 %6, %8 + %10 = bitcast i32* %1 to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %10) + store i32 %9, i32* %1 + %11 = load i32, i32* %1 + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %10) + %12 = getelementptr inbounds i32, i32 addrspace(1)* %res, i64 %4 + store i32 %11, i32 addrspace(1)* %12, align 4 + ret void +} + +; Function Attrs: nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #0 + +; Function Attrs: nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #0 + +; Function Attrs: nounwind readnone +declare spir_func i64 @_Z13get_global_idj(i32) #1 + +attributes #0 = { nounwind } +attributes #1 = { nounwind readnone } + +!opencl.kernels = !{!0} +!opencl.enable.FP_CONTRACT = !{} +!spirv.Source = !{!6} +!opencl.spir.version = !{!7} +!opencl.ocl.version = !{!7} +!opencl.used.extensions = !{!8} +!opencl.used.optional.core.features = !{!8} +!spirv.Generator = !{!9} + +!0 = !{void (i32 addrspace(1)*, i32 addrspace(1)*, i32 addrspace(1)*)* @lifetime_simple, !1, !2, !3, !4, !5} +!1 = !{!"kernel_arg_addr_space", i32 1, i32 1, i32 1} +!2 = !{!"kernel_arg_access_qual", !"none", !"none", !"none"} +!3 = !{!"kernel_arg_type", !"int*", !"int*", !"int*"} +!4 = !{!"kernel_arg_type_qual", !"", !"", !""} +!5 = !{!"kernel_arg_base_type", !"int*", !"int*", !"int*"} +!6 = !{i32 3, i32 102000} +!7 = !{i32 1, i32 2} +!8 = !{} +!9 = !{i16 7, i16 0} diff --git a/test/linkage-types.ll b/test/linkage-types.ll index bae9194..9e0ba2a 100644 --- a/test/linkage-types.ll +++ b/test/linkage-types.ll @@ -1,167 +1,167 @@ -; RUN: llvm-as < %s > %t.bc
-; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt
-; RUN: FileCheck < %t.txt %s --check-prefix=SPIRV
-; RUN: llvm-spirv %t.bc -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
-; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=BACK-TO-LLVM
-
-; ModuleID = 'c:/work/tmp/testLink.c'
-target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir-unknown-unknown"
-
-; SPIRV: Capability Linkage
-; SPIRV: EntryPoint 6 [[kern:[0-9]+]] "kern"
-
-@ae = available_externally addrspace(1) global i32 79, align 4
-; SPIRV: Name [[ae:[0-9]+]] "ae"
-; BACK-TO-LLVM: @ae = available_externally addrspace(1) global i32 79, align 4
-
-@i1 = addrspace(1) global i32 1, align 4
-; SPIRV: Name [[i1:[0-9]+]] "i1"
-; BACK-TO-LLVM: @i1 = addrspace(1) global i32 1, align 4
-
-@i2 = internal addrspace(1) global i32 2, align 4
-; SPIRV: Name [[i2:[0-9]+]] "i2"
-; BACK-TO-LLVM: @i2 = internal addrspace(1) global i32 2, align 4
-
-@i3 = addrspace(1) global i32 3, align 4
-; SPIRV: Name [[i3:[0-9]+]] "i3"
-; BACK-TO-LLVM: @i3 = addrspace(1) global i32 3, align 4
-
-@i4 = common addrspace(1) global i32 0, align 4
-; SPIRV: Name [[i4:[0-9]+]] "i4"
-; BACK-TO-LLVM: @i4 = common addrspace(1) global i32 0, align 4
-
-@i5 = internal addrspace(1) global i32 0, align 4
-; SPIRV: Name [[i5:[0-9]+]] "i5"
-; BACK-TO-LLVM: @i5 = internal addrspace(1) global i32 0, align 4
-
-@color_table = addrspace(2) constant [2 x i32] [i32 0, i32 1], align 4
-; SPIRV: Name [[color_table:[0-9]+]] "color_table"
-; BACK-TO-LLVM: @color_table = addrspace(2) constant [2 x i32] [i32 0, i32 1], align 4
-
-@noise_table = external addrspace(2) constant [256 x i32]
-; SPIRV: Name [[noise_table:[0-9]+]] "noise_table"
-; BACK-TO-LLVM: @noise_table = external addrspace(2) constant [256 x i32]
-
-@w = addrspace(1) constant i32 0, align 4
-; SPIRV: Name [[w:[0-9]+]] "w"
-; BACK-TO-LLVM: @w = addrspace(1) constant i32 0, align 4
-
-@f.color_table = internal addrspace(2) constant [2 x i32] [i32 2, i32 3], align 4
-; SPIRV: Name [[f_color_table:[0-9]+]] "f.color_table"
-; BACK-TO-LLVM: @f.color_table = internal addrspace(2) constant [2 x i32] [i32 2, i32 3], align 4
-
-@e = external addrspace(1) global i32
-; SPIRV: Name [[e:[0-9]+]] "e"
-; BACK-TO-LLVM: @e = external addrspace(1) global i32
-
-@f.t = internal addrspace(1) global i32 5, align 4
-; SPIRV: Name [[f_t:[0-9]+]] "f.t"
-; BACK-TO-LLVM: @f.t = internal addrspace(1) global i32 5, align 4
-
-@f.stint = internal addrspace(1) global i32 0, align 4
-; SPIRV: Name [[f_stint:[0-9]+]] "f.stint"
-; BACK-TO-LLVM: @f.stint = internal addrspace(1) global i32 0, align 4
-
-@f.inside = internal addrspace(1) global i32 0, align 4
-; SPIRV: Name [[f_inside:[0-9]+]] "f.inside"
-; BACK-TO-LLVM: @f.inside = internal addrspace(1) global i32 0, align 4
-
-@f.b = internal addrspace(2) constant float 1.000000e+00, align 4
-; SPIRV: Name [[f_b:[0-9]+]] "f.b"
-; BACK-TO-LLVM: @f.b = internal addrspace(2) constant float 1.000000e+00, align 4
-
-; SPIRV-DAG: Name [[foo:[0-9]+]] "foo"
-; SPIRV-DAG: Name [[f:[0-9]+]] "f"
-; SPIRV-DAG: Name [[g:[0-9]+]] "g"
-; SPIRV-DAG: Name [[inline_fun:[0-9]+]] "inline_fun"
-
-; SPIRV-DAG: Decorate [[ae]] LinkageAttributes "ae" Import
-; SPIRV-DAG: Decorate [[e]] LinkageAttributes "e" Import
-; SPIRV-DAG: Decorate [[f]] LinkageAttributes "f" Export
-; SPIRV-DAG: Decorate [[w]] LinkageAttributes "w" Export
-; SPIRV-DAG: Decorate [[i1]] LinkageAttributes "i1" Export
-; SPIRV-DAG: Decorate [[i3]] LinkageAttributes "i3" Export
-; SPIRV-DAG: Decorate [[i4]] LinkageAttributes "i4" Export
-; SPIRV-DAG: Decorate [[foo]] LinkageAttributes "foo" Import
-; SPIRV-DAG: Decorate [[inline_fun]] LinkageAttributes "inline_fun" Export
-; SPIRV-DAG: Decorate [[color_table]] LinkageAttributes "color_table" Export
-; SPIRV-DAG: Decorate [[noise_table]] LinkageAttributes "noise_table" Import
-
-; SPIRV: Function {{[0-9]+}} [[foo]]
-; BACK-TO-LLVM: declare spir_func void @foo()
-declare spir_func void @foo() #2
-
-; SPIRV: Function {{[0-9]+}} [[f]]
-; BACK-TO-LLVM: define spir_func void @f()
-; Function Attrs: nounwind
-define spir_func void @f() #0 {
-entry:
- %q = alloca i32, align 4
- %r = alloca i32, align 4
- %0 = load i32, i32 addrspace(1)* @i2, align 4
- store i32 %0, i32* %q, align 4
- %1 = load i32, i32 addrspace(1)* @i3, align 4
- store i32 %1, i32 addrspace(1)* @i5, align 4
- %2 = load i32, i32 addrspace(1)* @e, align 4
- store i32 %2, i32* %r, align 4
- %3 = load i32, i32 addrspace(2)* getelementptr inbounds ([256 x i32], [256 x i32] addrspace(2)* @noise_table, i32 0, i32 0), align 4
- store i32 %3, i32* %r, align 4
- %4 = load i32, i32 addrspace(2)* getelementptr inbounds ([2 x i32], [2 x i32] addrspace(2)* @f.color_table, i32 0, i32 0), align 4
- store i32 %4, i32* %r, align 4
- %call = call spir_func i32 @g()
- call spir_func void @inline_fun()
- ret void
-}
-
-; SPIRV: Function {{[0-9]+}} [[g]]
-; BACK-TO-LLVM: define internal spir_func i32 @g()
-; Function Attrs: nounwind
-define internal spir_func i32 @g() #0 {
-entry:
- call spir_func void @foo()
- ret i32 25
-}
-
-; SPIRV: Function {{[0-9]+}} [[inline_fun]]
-; BACK-TO-LLVM: define spir_func void @inline_fun()
-; "linkonce_odr" is lost in translation !
-; Function Attrs: inlinehint nounwind
-define linkonce_odr spir_func void @inline_fun() #1 {
-entry:
- %t = alloca i32 addrspace(1)*, align 4
- store i32 addrspace(1)* @i1, i32 addrspace(1)** %t, align 4
- ret void
-}
-
-; SPIRV: Function {{[0-9]+}} [[kern]]
-; BACK-TO-LLVM: define spir_kernel void @kern()
-; Function Attrs: nounwind
-define spir_kernel void @kern() #0 {
-entry:
- call spir_func void @f()
- ret void
-}
-
-attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #1 = { inlinehint nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-
-!opencl.kernels = !{!0}
-!opencl.enable.FP_CONTRACT = !{}
-!opencl.spir.version = !{!6}
-!opencl.ocl.version = !{!7}
-!opencl.used.extensions = !{!8}
-!opencl.used.optional.core.features = !{!8}
-!opencl.compiler.options = !{!8}
-
-!0 = !{void ()* @kern, !1, !2, !3, !4, !5}
-!1 = !{!"kernel_arg_addr_space"}
-!2 = !{!"kernel_arg_access_qual"}
-!3 = !{!"kernel_arg_type"}
-!4 = !{!"kernel_arg_base_type"}
-!5 = !{!"kernel_arg_type_qual"}
-!6 = !{i32 1, i32 2}
-!7 = !{i32 2, i32 0}
-!8 = !{}
+; RUN: llvm-as < %s > %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt +; RUN: FileCheck < %t.txt %s --check-prefix=SPIRV +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=BACK-TO-LLVM + +; ModuleID = 'c:/work/tmp/testLink.c' +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir-unknown-unknown" + +; SPIRV: Capability Linkage +; SPIRV: EntryPoint 6 [[kern:[0-9]+]] "kern" + +@ae = available_externally addrspace(1) global i32 79, align 4 +; SPIRV: Name [[ae:[0-9]+]] "ae" +; BACK-TO-LLVM: @ae = available_externally addrspace(1) global i32 79, align 4 + +@i1 = addrspace(1) global i32 1, align 4 +; SPIRV: Name [[i1:[0-9]+]] "i1" +; BACK-TO-LLVM: @i1 = addrspace(1) global i32 1, align 4 + +@i2 = internal addrspace(1) global i32 2, align 4 +; SPIRV: Name [[i2:[0-9]+]] "i2" +; BACK-TO-LLVM: @i2 = internal addrspace(1) global i32 2, align 4 + +@i3 = addrspace(1) global i32 3, align 4 +; SPIRV: Name [[i3:[0-9]+]] "i3" +; BACK-TO-LLVM: @i3 = addrspace(1) global i32 3, align 4 + +@i4 = common addrspace(1) global i32 0, align 4 +; SPIRV: Name [[i4:[0-9]+]] "i4" +; BACK-TO-LLVM: @i4 = common addrspace(1) global i32 0, align 4 + +@i5 = internal addrspace(1) global i32 0, align 4 +; SPIRV: Name [[i5:[0-9]+]] "i5" +; BACK-TO-LLVM: @i5 = internal addrspace(1) global i32 0, align 4 + +@color_table = addrspace(2) constant [2 x i32] [i32 0, i32 1], align 4 +; SPIRV: Name [[color_table:[0-9]+]] "color_table" +; BACK-TO-LLVM: @color_table = addrspace(2) constant [2 x i32] [i32 0, i32 1], align 4 + +@noise_table = external addrspace(2) constant [256 x i32] +; SPIRV: Name [[noise_table:[0-9]+]] "noise_table" +; BACK-TO-LLVM: @noise_table = external addrspace(2) constant [256 x i32] + +@w = addrspace(1) constant i32 0, align 4 +; SPIRV: Name [[w:[0-9]+]] "w" +; BACK-TO-LLVM: @w = addrspace(1) constant i32 0, align 4 + +@f.color_table = internal addrspace(2) constant [2 x i32] [i32 2, i32 3], align 4 +; SPIRV: Name [[f_color_table:[0-9]+]] "f.color_table" +; BACK-TO-LLVM: @f.color_table = internal addrspace(2) constant [2 x i32] [i32 2, i32 3], align 4 + +@e = external addrspace(1) global i32 +; SPIRV: Name [[e:[0-9]+]] "e" +; BACK-TO-LLVM: @e = external addrspace(1) global i32 + +@f.t = internal addrspace(1) global i32 5, align 4 +; SPIRV: Name [[f_t:[0-9]+]] "f.t" +; BACK-TO-LLVM: @f.t = internal addrspace(1) global i32 5, align 4 + +@f.stint = internal addrspace(1) global i32 0, align 4 +; SPIRV: Name [[f_stint:[0-9]+]] "f.stint" +; BACK-TO-LLVM: @f.stint = internal addrspace(1) global i32 0, align 4 + +@f.inside = internal addrspace(1) global i32 0, align 4 +; SPIRV: Name [[f_inside:[0-9]+]] "f.inside" +; BACK-TO-LLVM: @f.inside = internal addrspace(1) global i32 0, align 4 + +@f.b = internal addrspace(2) constant float 1.000000e+00, align 4 +; SPIRV: Name [[f_b:[0-9]+]] "f.b" +; BACK-TO-LLVM: @f.b = internal addrspace(2) constant float 1.000000e+00, align 4 + +; SPIRV-DAG: Name [[foo:[0-9]+]] "foo" +; SPIRV-DAG: Name [[f:[0-9]+]] "f" +; SPIRV-DAG: Name [[g:[0-9]+]] "g" +; SPIRV-DAG: Name [[inline_fun:[0-9]+]] "inline_fun" + +; SPIRV-DAG: Decorate [[ae]] LinkageAttributes "ae" Import +; SPIRV-DAG: Decorate [[e]] LinkageAttributes "e" Import +; SPIRV-DAG: Decorate [[f]] LinkageAttributes "f" Export +; SPIRV-DAG: Decorate [[w]] LinkageAttributes "w" Export +; SPIRV-DAG: Decorate [[i1]] LinkageAttributes "i1" Export +; SPIRV-DAG: Decorate [[i3]] LinkageAttributes "i3" Export +; SPIRV-DAG: Decorate [[i4]] LinkageAttributes "i4" Export +; SPIRV-DAG: Decorate [[foo]] LinkageAttributes "foo" Import +; SPIRV-DAG: Decorate [[inline_fun]] LinkageAttributes "inline_fun" Export +; SPIRV-DAG: Decorate [[color_table]] LinkageAttributes "color_table" Export +; SPIRV-DAG: Decorate [[noise_table]] LinkageAttributes "noise_table" Import + +; SPIRV: Function {{[0-9]+}} [[foo]] +; BACK-TO-LLVM: declare spir_func void @foo() +declare spir_func void @foo() #2 + +; SPIRV: Function {{[0-9]+}} [[f]] +; BACK-TO-LLVM: define spir_func void @f() +; Function Attrs: nounwind +define spir_func void @f() #0 { +entry: + %q = alloca i32, align 4 + %r = alloca i32, align 4 + %0 = load i32, i32 addrspace(1)* @i2, align 4 + store i32 %0, i32* %q, align 4 + %1 = load i32, i32 addrspace(1)* @i3, align 4 + store i32 %1, i32 addrspace(1)* @i5, align 4 + %2 = load i32, i32 addrspace(1)* @e, align 4 + store i32 %2, i32* %r, align 4 + %3 = load i32, i32 addrspace(2)* getelementptr inbounds ([256 x i32], [256 x i32] addrspace(2)* @noise_table, i32 0, i32 0), align 4 + store i32 %3, i32* %r, align 4 + %4 = load i32, i32 addrspace(2)* getelementptr inbounds ([2 x i32], [2 x i32] addrspace(2)* @f.color_table, i32 0, i32 0), align 4 + store i32 %4, i32* %r, align 4 + %call = call spir_func i32 @g() + call spir_func void @inline_fun() + ret void +} + +; SPIRV: Function {{[0-9]+}} [[g]] +; BACK-TO-LLVM: define internal spir_func i32 @g() +; Function Attrs: nounwind +define internal spir_func i32 @g() #0 { +entry: + call spir_func void @foo() + ret i32 25 +} + +; SPIRV: Function {{[0-9]+}} [[inline_fun]] +; BACK-TO-LLVM: define spir_func void @inline_fun() +; "linkonce_odr" is lost in translation ! +; Function Attrs: inlinehint nounwind +define linkonce_odr spir_func void @inline_fun() #1 { +entry: + %t = alloca i32 addrspace(1)*, align 4 + store i32 addrspace(1)* @i1, i32 addrspace(1)** %t, align 4 + ret void +} + +; SPIRV: Function {{[0-9]+}} [[kern]] +; BACK-TO-LLVM: define spir_kernel void @kern() +; Function Attrs: nounwind +define spir_kernel void @kern() #0 { +entry: + call spir_func void @f() + ret void +} + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { inlinehint nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!opencl.kernels = !{!0} +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!6} +!opencl.ocl.version = !{!7} +!opencl.used.extensions = !{!8} +!opencl.used.optional.core.features = !{!8} +!opencl.compiler.options = !{!8} + +!0 = !{void ()* @kern, !1, !2, !3, !4, !5} +!1 = !{!"kernel_arg_addr_space"} +!2 = !{!"kernel_arg_access_qual"} +!3 = !{!"kernel_arg_type"} +!4 = !{!"kernel_arg_base_type"} +!5 = !{!"kernel_arg_type_qual"} +!6 = !{i32 1, i32 2} +!7 = !{i32 2, i32 0} +!8 = !{} diff --git a/test/selection_merge.spt b/test/selection_merge.spt index 2d6828b..9a236da 100644 --- a/test/selection_merge.spt +++ b/test/selection_merge.spt @@ -1,74 +1,74 @@ -119734787 65536 458752 36 0
-2 Capability Addresses
-2 Capability Linkage
-2 Capability Kernel
-2 Capability Int64
-3 MemoryModel 2 2
-9 EntryPoint 6 1 "select_if_dont_flatten"
-3 Source 3 102000
-3 Name 2 "res"
-3 Name 3 "lhs"
-3 Name 4 "rhs"
-4 Decorate 5 FuncParamAttr 5
-2 DecorationGroup 5
-4 Decorate 6 BuiltIn 28
-3 Decorate 6 Constant
-11 Decorate 6 LinkageAttributes "__spirv_GlobalInvocationId" Import
-5 GroupDecorate 5 2 3 4
-4 TypeInt 7 64 0
-4 TypeInt 12 32 1
-5 Constant 7 13 32 0
-4 Constant 12 14 0
-4 TypeVector 8 7 3
-4 TypePointer 9 0 8
-2 TypeBool 10
-2 TypeVoid 11
-4 TypePointer 15 5 12
-4 TypePointer 16 7 12
-6 TypeFunction 17 11 15 15 15
-4 Variable 9 6 0
-
-5 Function 11 1 0 17
-3 FunctionParameter 15 2
-3 FunctionParameter 15 3
-3 FunctionParameter 15 4
-
-2 Label 18
-6 Load 8 19 6 2 0
-5 CompositeExtract 7 20 19 0
-5 ShiftLeftLogical 7 21 20 13
-5 ShiftRightArithmetic 7 22 21 13
-5 InBoundsPtrAccessChain 15 23 3 22
-6 Load 12 24 23 2 4
-5 InBoundsPtrAccessChain 15 25 4 22
-6 Load 12 26 25 2 4
-4 Variable 16 27 7
-3 Store 27 14
-5 SLessThan 10 28 24 26
-3 SelectionMerge 29 2
-4 BranchConditional 28 30 31
-
-2 Label 30
-5 ISub 12 32 26 24
-3 Store 27 32
-2 Branch 29
-
-2 Label 31
-5 ISub 12 33 24 26
-3 Store 27 33
-2 Branch 29
-
-2 Label 29
-4 Load 12 34 27
-5 InBoundsPtrAccessChain 15 35 2 22
-5 Store 35 34 2 4
-1 Return
-
-1 FunctionEnd
-; RUN: llvm-spirv %s -to-binary -o %t.spv
-; RUN: llvm-spirv %t.spv -to-text -o %t.spt
-; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
-; RUN: llvm-spirv -r %t.spv -o %t.bc
-
-; CHECK-SPIRV: 3 SelectionMerge {{[0-9]*}} 2
+119734787 65536 458752 36 0 +2 Capability Addresses +2 Capability Linkage +2 Capability Kernel +2 Capability Int64 +3 MemoryModel 2 2 +9 EntryPoint 6 1 "select_if_dont_flatten" +3 Source 3 102000 +3 Name 2 "res" +3 Name 3 "lhs" +3 Name 4 "rhs" +4 Decorate 5 FuncParamAttr 5 +2 DecorationGroup 5 +4 Decorate 6 BuiltIn 28 +3 Decorate 6 Constant +11 Decorate 6 LinkageAttributes "__spirv_GlobalInvocationId" Import +5 GroupDecorate 5 2 3 4 +4 TypeInt 7 64 0 +4 TypeInt 12 32 1 +5 Constant 7 13 32 0 +4 Constant 12 14 0 +4 TypeVector 8 7 3 +4 TypePointer 9 0 8 +2 TypeBool 10 +2 TypeVoid 11 +4 TypePointer 15 5 12 +4 TypePointer 16 7 12 +6 TypeFunction 17 11 15 15 15 +4 Variable 9 6 0 + +5 Function 11 1 0 17 +3 FunctionParameter 15 2 +3 FunctionParameter 15 3 +3 FunctionParameter 15 4 + +2 Label 18 +6 Load 8 19 6 2 0 +5 CompositeExtract 7 20 19 0 +5 ShiftLeftLogical 7 21 20 13 +5 ShiftRightArithmetic 7 22 21 13 +5 InBoundsPtrAccessChain 15 23 3 22 +6 Load 12 24 23 2 4 +5 InBoundsPtrAccessChain 15 25 4 22 +6 Load 12 26 25 2 4 +4 Variable 16 27 7 +3 Store 27 14 +5 SLessThan 10 28 24 26 +3 SelectionMerge 29 2 +4 BranchConditional 28 30 31 + +2 Label 30 +5 ISub 12 32 26 24 +3 Store 27 32 +2 Branch 29 + +2 Label 31 +5 ISub 12 33 24 26 +3 Store 27 33 +2 Branch 29 + +2 Label 29 +4 Load 12 34 27 +5 InBoundsPtrAccessChain 15 35 2 22 +5 Store 35 34 2 4 +1 Return + +1 FunctionEnd +; RUN: llvm-spirv %s -to-binary -o %t.spv +; RUN: llvm-spirv %t.spv -to-text -o %t.spt +; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv -r %t.spv -o %t.bc + +; CHECK-SPIRV: 3 SelectionMerge {{[0-9]*}} 2 ; CHECK-SPIRV-NEXT: 4 BranchConditional {{[0-9]*}} {{[0-9]*}} {{[0-9]*}}
\ No newline at end of file diff --git a/test/simple.ll b/test/simple.ll index ff4d26b..153ff2c 100644 --- a/test/simple.ll +++ b/test/simple.ll @@ -1,158 +1,158 @@ -; RUN: llvm-as < %s | llvm-spirv -spirv-text -o %t
-; RUN: FileCheck < %t %s
-target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir64-unknown-unknown"
-
-; Support of doubles is required.
-; CHECK: Capability Float64
-; CHECK: "fun01"
-; Function Attrs: nounwind
-define spir_kernel void @fun01(i32 addrspace(1)* noalias %a, i32 addrspace(1)* %b, i32 %c) #0 {
-entry:
- %a.addr = alloca i32 addrspace(1)*, align 8
- %b.addr = alloca i32 addrspace(1)*, align 8
- %c.addr = alloca i32, align 4
- store i32 addrspace(1)* %a, i32 addrspace(1)** %a.addr, align 8
- store i32 addrspace(1)* %b, i32 addrspace(1)** %b.addr, align 8
- store i32 %c, i32* %c.addr, align 4
- %0 = load i32 addrspace(1)*, i32 addrspace(1)** %b.addr, align 8
- %arrayidx = getelementptr inbounds i32, i32 addrspace(1)* %0, i64 0
- %1 = load i32, i32 addrspace(1)* %arrayidx, align 4
- %2 = load i32 addrspace(1)*, i32 addrspace(1)** %a.addr, align 8
- %arrayidx1 = getelementptr inbounds i32, i32 addrspace(1)* %2, i64 0
- store i32 %1, i32 addrspace(1)* %arrayidx1, align 4
- %3 = load i32 addrspace(1)*, i32 addrspace(1)** %b.addr, align 8
- %cmp = icmp ugt i32 addrspace(1)* %3, null
- br i1 %cmp, label %if.then, label %if.end
-
-if.then: ; preds = %entry
- %4 = load i32 addrspace(1)*, i32 addrspace(1)** %a.addr, align 8
- %arrayidx2 = getelementptr inbounds i32, i32 addrspace(1)* %4, i64 0
- store i32 2, i32 addrspace(1)* %arrayidx2, align 4
- br label %if.end
-
-if.end: ; preds = %if.then, %entry
- ret void
-}
-
-; CHECK: "fun02"
-; Function Attrs: nounwind
-define spir_kernel void @fun02(double addrspace(1)* %a, double addrspace(1)* %b, i32 %c) #0 {
-entry:
- %a.addr = alloca double addrspace(1)*, align 8
- %b.addr = alloca double addrspace(1)*, align 8
- %c.addr = alloca i32, align 4
- store double addrspace(1)* %a, double addrspace(1)** %a.addr, align 8
- store double addrspace(1)* %b, double addrspace(1)** %b.addr, align 8
- store i32 %c, i32* %c.addr, align 4
- %0 = load i32, i32* %c.addr, align 4
- %idxprom = sext i32 %0 to i64
- %1 = load double addrspace(1)*, double addrspace(1)** %b.addr, align 8
- %arrayidx = getelementptr inbounds double, double addrspace(1)* %1, i64 %idxprom
- %2 = load double, double addrspace(1)* %arrayidx, align 8
- %3 = load i32, i32* %c.addr, align 4
- %idxprom1 = sext i32 %3 to i64
- %4 = load double addrspace(1)*, double addrspace(1)** %a.addr, align 8
- %arrayidx2 = getelementptr inbounds double, double addrspace(1)* %4, i64 %idxprom1
- store double %2, double addrspace(1)* %arrayidx2, align 8
- ret void
-}
-
-; CHECK: "test_builtin"
-; Function Attrs: nounwind
-define spir_func void @test_builtin(i32 addrspace(1)* %in, i32 addrspace(1)* %out) #0 {
-entry:
- %in.addr = alloca i32 addrspace(1)*, align 8
- %out.addr = alloca i32 addrspace(1)*, align 8
- %n = alloca i32, align 4
- store i32 addrspace(1)* %in, i32 addrspace(1)** %in.addr, align 8
- store i32 addrspace(1)* %out, i32 addrspace(1)** %out.addr, align 8
- %call = call spir_func i64 @_Z13get_global_idj(i32 0) #2
- %conv = trunc i64 %call to i32
- store i32 %conv, i32* %n, align 4
- %0 = load i32, i32* %n, align 4
- %idxprom = sext i32 %0 to i64
- %1 = load i32 addrspace(1)*, i32 addrspace(1)** %in.addr, align 8
- %arrayidx = getelementptr inbounds i32, i32 addrspace(1)* %1, i64 %idxprom
- %2 = load i32, i32 addrspace(1)* %arrayidx, align 4
- %call1 = call spir_func i32 @_Z3absi(i32 %2) #2
- %3 = load i32, i32* %n, align 4
- %idxprom2 = sext i32 %3 to i64
- %4 = load i32 addrspace(1)*, i32 addrspace(1)** %out.addr, align 8
- %arrayidx3 = getelementptr inbounds i32, i32 addrspace(1)* %4, i64 %idxprom2
- store i32 %call1, i32 addrspace(1)* %arrayidx3, align 4
- ret void
-}
-
-; CHECK-NOT: "_Z13get_global_idj"
-; Function Attrs: nounwind readnone
-declare spir_func i64 @_Z13get_global_idj(i32) #1
-
-; CHECK-NOT: "_Z3absi"
-; Function Attrs: nounwind readnone
-declare spir_func i32 @_Z3absi(i32) #1
-
-; CHECK: "myabs"
-; Function Attrs: nounwind
-define spir_func i32 @myabs(i32 %x) #0 {
-entry:
- %x.addr = alloca i32, align 4
- store i32 %x, i32* %x.addr, align 4
- %0 = load i32, i32* %x.addr, align 4
- %call = call spir_func i32 @_Z3absi(i32 %0) #2
- ret i32 %call
-}
-
-; CHECK: "test_function_call"
-; Function Attrs: nounwind
-define spir_func void @test_function_call(i32 addrspace(1)* %in, i32 addrspace(1)* %out) #0 {
-entry:
- %in.addr = alloca i32 addrspace(1)*, align 8
- %out.addr = alloca i32 addrspace(1)*, align 8
- %n = alloca i32, align 4
- store i32 addrspace(1)* %in, i32 addrspace(1)** %in.addr, align 8
- store i32 addrspace(1)* %out, i32 addrspace(1)** %out.addr, align 8
- %call = call spir_func i64 @_Z13get_global_idj(i32 0) #2
- %conv = trunc i64 %call to i32
- store i32 %conv, i32* %n, align 4
- %0 = load i32, i32* %n, align 4
- %idxprom = sext i32 %0 to i64
- %1 = load i32 addrspace(1)*, i32 addrspace(1)** %in.addr, align 8
- %arrayidx = getelementptr inbounds i32, i32 addrspace(1)* %1, i64 %idxprom
- %2 = load i32, i32 addrspace(1)* %arrayidx, align 4
- %call1 = call spir_func i32 @myabs(i32 %2)
- %3 = load i32, i32* %n, align 4
- %idxprom2 = sext i32 %3 to i64
- %4 = load i32 addrspace(1)*, i32 addrspace(1)** %out.addr, align 8
- %arrayidx3 = getelementptr inbounds i32, i32 addrspace(1)* %4, i64 %idxprom2
- store i32 %call1, i32 addrspace(1)* %arrayidx3, align 4
- ret void
-}
-
-attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #1 = { nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #2 = { nounwind readnone }
-
-!opencl.kernels = !{!0, !7}
-!opencl.enable.FP_CONTRACT = !{}
-!opencl.spir.version = !{!12}
-!opencl.ocl.version = !{!12}
-!opencl.used.extensions = !{!13}
-!opencl.used.optional.core.features = !{!14}
-!opencl.compiler.options = !{!13}
-
-!0 = !{void (i32 addrspace(1)*, i32 addrspace(1)*, i32)* @fun01, !1, !2, !3, !4, !5, !6}
-!1 = !{!"kernel_arg_addr_space", i32 1, i32 1, i32 0}
-!2 = !{!"kernel_arg_access_qual", !"none", !"none", !"none"}
-!3 = !{!"kernel_arg_type", !"int*", !"int*", !"int"}
-!4 = !{!"kernel_arg_base_type", !"int*", !"int*", !"int"}
-!5 = !{!"kernel_arg_type_qual", !"restrict", !"const", !""}
-!6 = !{!"reqd_work_group_size", i32 1, i32 2, i32 3}
-!7 = !{void (double addrspace(1)*, double addrspace(1)*, i32)* @fun02, !1, !2, !8, !9, !10, !11}
-!8 = !{!"kernel_arg_type", !"double*", !"double*", !"int"}
-!9 = !{!"kernel_arg_base_type", !"double*", !"double*", !"int"}
-!10 = !{!"kernel_arg_type_qual", !"", !"", !""}
-!11 = !{!"vec_type_hint", double undef, i32 1}
-!12 = !{i32 1, i32 2}
-!13 = !{}
-!14 = !{!"cl_doubles"}
+; RUN: llvm-as < %s | llvm-spirv -spirv-text -o %t +; RUN: FileCheck < %t %s +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir64-unknown-unknown" + +; Support of doubles is required. +; CHECK: Capability Float64 +; CHECK: "fun01" +; Function Attrs: nounwind +define spir_kernel void @fun01(i32 addrspace(1)* noalias %a, i32 addrspace(1)* %b, i32 %c) #0 { +entry: + %a.addr = alloca i32 addrspace(1)*, align 8 + %b.addr = alloca i32 addrspace(1)*, align 8 + %c.addr = alloca i32, align 4 + store i32 addrspace(1)* %a, i32 addrspace(1)** %a.addr, align 8 + store i32 addrspace(1)* %b, i32 addrspace(1)** %b.addr, align 8 + store i32 %c, i32* %c.addr, align 4 + %0 = load i32 addrspace(1)*, i32 addrspace(1)** %b.addr, align 8 + %arrayidx = getelementptr inbounds i32, i32 addrspace(1)* %0, i64 0 + %1 = load i32, i32 addrspace(1)* %arrayidx, align 4 + %2 = load i32 addrspace(1)*, i32 addrspace(1)** %a.addr, align 8 + %arrayidx1 = getelementptr inbounds i32, i32 addrspace(1)* %2, i64 0 + store i32 %1, i32 addrspace(1)* %arrayidx1, align 4 + %3 = load i32 addrspace(1)*, i32 addrspace(1)** %b.addr, align 8 + %cmp = icmp ugt i32 addrspace(1)* %3, null + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + %4 = load i32 addrspace(1)*, i32 addrspace(1)** %a.addr, align 8 + %arrayidx2 = getelementptr inbounds i32, i32 addrspace(1)* %4, i64 0 + store i32 2, i32 addrspace(1)* %arrayidx2, align 4 + br label %if.end + +if.end: ; preds = %if.then, %entry + ret void +} + +; CHECK: "fun02" +; Function Attrs: nounwind +define spir_kernel void @fun02(double addrspace(1)* %a, double addrspace(1)* %b, i32 %c) #0 { +entry: + %a.addr = alloca double addrspace(1)*, align 8 + %b.addr = alloca double addrspace(1)*, align 8 + %c.addr = alloca i32, align 4 + store double addrspace(1)* %a, double addrspace(1)** %a.addr, align 8 + store double addrspace(1)* %b, double addrspace(1)** %b.addr, align 8 + store i32 %c, i32* %c.addr, align 4 + %0 = load i32, i32* %c.addr, align 4 + %idxprom = sext i32 %0 to i64 + %1 = load double addrspace(1)*, double addrspace(1)** %b.addr, align 8 + %arrayidx = getelementptr inbounds double, double addrspace(1)* %1, i64 %idxprom + %2 = load double, double addrspace(1)* %arrayidx, align 8 + %3 = load i32, i32* %c.addr, align 4 + %idxprom1 = sext i32 %3 to i64 + %4 = load double addrspace(1)*, double addrspace(1)** %a.addr, align 8 + %arrayidx2 = getelementptr inbounds double, double addrspace(1)* %4, i64 %idxprom1 + store double %2, double addrspace(1)* %arrayidx2, align 8 + ret void +} + +; CHECK: "test_builtin" +; Function Attrs: nounwind +define spir_func void @test_builtin(i32 addrspace(1)* %in, i32 addrspace(1)* %out) #0 { +entry: + %in.addr = alloca i32 addrspace(1)*, align 8 + %out.addr = alloca i32 addrspace(1)*, align 8 + %n = alloca i32, align 4 + store i32 addrspace(1)* %in, i32 addrspace(1)** %in.addr, align 8 + store i32 addrspace(1)* %out, i32 addrspace(1)** %out.addr, align 8 + %call = call spir_func i64 @_Z13get_global_idj(i32 0) #2 + %conv = trunc i64 %call to i32 + store i32 %conv, i32* %n, align 4 + %0 = load i32, i32* %n, align 4 + %idxprom = sext i32 %0 to i64 + %1 = load i32 addrspace(1)*, i32 addrspace(1)** %in.addr, align 8 + %arrayidx = getelementptr inbounds i32, i32 addrspace(1)* %1, i64 %idxprom + %2 = load i32, i32 addrspace(1)* %arrayidx, align 4 + %call1 = call spir_func i32 @_Z3absi(i32 %2) #2 + %3 = load i32, i32* %n, align 4 + %idxprom2 = sext i32 %3 to i64 + %4 = load i32 addrspace(1)*, i32 addrspace(1)** %out.addr, align 8 + %arrayidx3 = getelementptr inbounds i32, i32 addrspace(1)* %4, i64 %idxprom2 + store i32 %call1, i32 addrspace(1)* %arrayidx3, align 4 + ret void +} + +; CHECK-NOT: "_Z13get_global_idj" +; Function Attrs: nounwind readnone +declare spir_func i64 @_Z13get_global_idj(i32) #1 + +; CHECK-NOT: "_Z3absi" +; Function Attrs: nounwind readnone +declare spir_func i32 @_Z3absi(i32) #1 + +; CHECK: "myabs" +; Function Attrs: nounwind +define spir_func i32 @myabs(i32 %x) #0 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, i32* %x.addr, align 4 + %0 = load i32, i32* %x.addr, align 4 + %call = call spir_func i32 @_Z3absi(i32 %0) #2 + ret i32 %call +} + +; CHECK: "test_function_call" +; Function Attrs: nounwind +define spir_func void @test_function_call(i32 addrspace(1)* %in, i32 addrspace(1)* %out) #0 { +entry: + %in.addr = alloca i32 addrspace(1)*, align 8 + %out.addr = alloca i32 addrspace(1)*, align 8 + %n = alloca i32, align 4 + store i32 addrspace(1)* %in, i32 addrspace(1)** %in.addr, align 8 + store i32 addrspace(1)* %out, i32 addrspace(1)** %out.addr, align 8 + %call = call spir_func i64 @_Z13get_global_idj(i32 0) #2 + %conv = trunc i64 %call to i32 + store i32 %conv, i32* %n, align 4 + %0 = load i32, i32* %n, align 4 + %idxprom = sext i32 %0 to i64 + %1 = load i32 addrspace(1)*, i32 addrspace(1)** %in.addr, align 8 + %arrayidx = getelementptr inbounds i32, i32 addrspace(1)* %1, i64 %idxprom + %2 = load i32, i32 addrspace(1)* %arrayidx, align 4 + %call1 = call spir_func i32 @myabs(i32 %2) + %3 = load i32, i32* %n, align 4 + %idxprom2 = sext i32 %3 to i64 + %4 = load i32 addrspace(1)*, i32 addrspace(1)** %out.addr, align 8 + %arrayidx3 = getelementptr inbounds i32, i32 addrspace(1)* %4, i64 %idxprom2 + store i32 %call1, i32 addrspace(1)* %arrayidx3, align 4 + ret void +} + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } + +!opencl.kernels = !{!0, !7} +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!12} +!opencl.ocl.version = !{!12} +!opencl.used.extensions = !{!13} +!opencl.used.optional.core.features = !{!14} +!opencl.compiler.options = !{!13} + +!0 = !{void (i32 addrspace(1)*, i32 addrspace(1)*, i32)* @fun01, !1, !2, !3, !4, !5, !6} +!1 = !{!"kernel_arg_addr_space", i32 1, i32 1, i32 0} +!2 = !{!"kernel_arg_access_qual", !"none", !"none", !"none"} +!3 = !{!"kernel_arg_type", !"int*", !"int*", !"int"} +!4 = !{!"kernel_arg_base_type", !"int*", !"int*", !"int"} +!5 = !{!"kernel_arg_type_qual", !"restrict", !"const", !""} +!6 = !{!"reqd_work_group_size", i32 1, i32 2, i32 3} +!7 = !{void (double addrspace(1)*, double addrspace(1)*, i32)* @fun02, !1, !2, !8, !9, !10, !11} +!8 = !{!"kernel_arg_type", !"double*", !"double*", !"int"} +!9 = !{!"kernel_arg_base_type", !"double*", !"double*", !"int"} +!10 = !{!"kernel_arg_type_qual", !"", !"", !""} +!11 = !{!"vec_type_hint", double undef, i32 1} +!12 = !{i32 1, i32 2} +!13 = !{} +!14 = !{!"cl_doubles"} diff --git a/test/transcoding/DecorationMaxByteOffset.ll b/test/transcoding/DecorationMaxByteOffset.ll index a9caba5..dabccfb 100644 --- a/test/transcoding/DecorationMaxByteOffset.ll +++ b/test/transcoding/DecorationMaxByteOffset.ll @@ -1,53 +1,53 @@ -; RUN: llvm-as %s -o %t.bc
-; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt
-; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV
-; RUN: llvm-spirv %t.bc -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
-; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-LLVM: define spir_kernel void @worker(i8 addrspace(3)* dereferenceable(12) %ptr)
-; CHECK-LLVM: define spir_func void @not_a_kernel(i8 addrspace(3)* dereferenceable(123) %ptr2)
-
-; CHECK-SPIRV: 3 Name [[PTR_ID:[0-9]+]] "ptr"
-; CHECK-SPIRV: 4 Name [[PTR2_ID:[0-9]+]] "ptr2"
-; CHECK-SPIRV: 4 Decorate [[PTR_ID]] MaxByteOffset 12
-; CHECK-SPIRV: 4 Decorate [[PTR2_ID]] MaxByteOffset 123
-; CHECK-SPIRV: 4 TypeInt [[CHAR_T:[0-9]+]] 8 0
-; CHECK-SPIRV: 4 TypePointer [[CHAR_PTR_T:[0-9]+]] 4 [[CHAR_T]]
-; CHECK-SPIRV: 3 FunctionParameter [[CHAR_PTR_T]] [[PTR_ID]]
-; CHECK-SPIRV: 3 FunctionParameter [[CHAR_PTR_T]] [[PTR2_ID]]
-
-target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir-unknown-unknown"
-
-; Function Attrs: nounwind
-define spir_kernel void @worker(i8 addrspace(3)* dereferenceable(12) %ptr) #0 {
-entry:
- %ptr.addr = alloca i8 addrspace(3)*, align 4
- store i8 addrspace(3)* %ptr, i8 addrspace(3)** %ptr.addr, align 4
- ret void
-}
-
-; Function Attrs: nounwind
-define spir_func void @not_a_kernel(i8 addrspace(3)* dereferenceable(123) %ptr2) #0 {
-entry:
- ret void
-}
-
-attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
-
-!opencl.enable.FP_CONTRACT = !{}
-!opencl.spir.version = !{!0}
-!opencl.ocl.version = !{!1}
-!opencl.used.extensions = !{!2}
-!opencl.used.optional.core.features = !{!2}
-!opencl.compiler.options = !{!2}
-!llvm.ident = !{!3}
-!spirv.Source = !{!4}
-!spirv.String = !{}
-
-!0 = !{i32 1, i32 2}
-!1 = !{i32 2, i32 2}
-!2 = !{}
-!3 = !{!"clang version 3.6.1 "}
-!4 = !{i32 4, i32 202000}
+; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt +; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-LLVM: define spir_kernel void @worker(i8 addrspace(3)* dereferenceable(12) %ptr) +; CHECK-LLVM: define spir_func void @not_a_kernel(i8 addrspace(3)* dereferenceable(123) %ptr2) + +; CHECK-SPIRV: 3 Name [[PTR_ID:[0-9]+]] "ptr" +; CHECK-SPIRV: 4 Name [[PTR2_ID:[0-9]+]] "ptr2" +; CHECK-SPIRV: 4 Decorate [[PTR_ID]] MaxByteOffset 12 +; CHECK-SPIRV: 4 Decorate [[PTR2_ID]] MaxByteOffset 123 +; CHECK-SPIRV: 4 TypeInt [[CHAR_T:[0-9]+]] 8 0 +; CHECK-SPIRV: 4 TypePointer [[CHAR_PTR_T:[0-9]+]] 4 [[CHAR_T]] +; CHECK-SPIRV: 3 FunctionParameter [[CHAR_PTR_T]] [[PTR_ID]] +; CHECK-SPIRV: 3 FunctionParameter [[CHAR_PTR_T]] [[PTR2_ID]] + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir-unknown-unknown" + +; Function Attrs: nounwind +define spir_kernel void @worker(i8 addrspace(3)* dereferenceable(12) %ptr) #0 { +entry: + %ptr.addr = alloca i8 addrspace(3)*, align 4 + store i8 addrspace(3)* %ptr, i8 addrspace(3)** %ptr.addr, align 4 + ret void +} + +; Function Attrs: nounwind +define spir_func void @not_a_kernel(i8 addrspace(3)* dereferenceable(123) %ptr2) #0 { +entry: + ret void +} + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!0} +!opencl.ocl.version = !{!1} +!opencl.used.extensions = !{!2} +!opencl.used.optional.core.features = !{!2} +!opencl.compiler.options = !{!2} +!llvm.ident = !{!3} +!spirv.Source = !{!4} +!spirv.String = !{} + +!0 = !{i32 1, i32 2} +!1 = !{i32 2, i32 2} +!2 = !{} +!3 = !{!"clang version 3.6.1 "} +!4 = !{i32 4, i32 202000} diff --git a/test/transcoding/check_ro_qualifier.ll b/test/transcoding/check_ro_qualifier.ll index 1092f15..326070c 100644 --- a/test/transcoding/check_ro_qualifier.ll +++ b/test/transcoding/check_ro_qualifier.ll @@ -1,66 +1,66 @@ -; RUN: llvm-as %s -o %t.bc
-; RUN: llvm-spirv %t.bc -o %t.spv
-; RUN: llvm-spirv -r -spirv-gen-image-type-acc-postfix %t.spv -o %t.rev.bc
-; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-LLVM: opencl.image2d_array_ro_t = type opaque
-; CHECK-LLVM: define spir_kernel void @sample_kernel(%opencl.image2d_array_ro_t addrspace(1)
-; CHECK-LLVM-SAME: !kernel_arg_access_qual [[AQ:![0-9]+]]
-; CHECK-LLVM-SAME: !kernel_arg_type [[TYPE:![0-9]+]]
-; CHECK-LLVM-SAME: !kernel_arg_base_type [[BT:![0-9]+]]
-
-; CHECK-LLVM: call spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1)
-; CHECK-LLVM: call spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1)
-; CHECK-LLVM: declare spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1)
-; CHECK-LLVM: declare spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1)
-
-; CHECK-LLVM-DAG: [[AQ]] = !{!"read_only"}
-; CHECK-LLVM-DAG: [[TYPE]] = !{!"image2d_array_ro_t"}
-; CHECK-LLVM-DAG: [[BT]] = !{!"image2d_array_ro_t"}
-
-; ModuleID = 'out.ll'
-target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir64-unknown-unknown"
-
-%opencl.image2d_array_ro_t = type opaque
-
-; Function Attrs: nounwind
-define spir_kernel void @sample_kernel(%opencl.image2d_array_ro_t addrspace(1)* %input) #0 {
-entry:
- %call.tmp1 = call spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1)* %input)
- %call.tmp2 = shufflevector <2 x i32> %call.tmp1, <2 x i32> undef, <3 x i32> <i32 0, i32 1, i32 2>
- %call.tmp3 = call spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1)* %input)
- %call.tmp4 = trunc i64 %call.tmp3 to i32
- %call.tmp5 = insertelement <3 x i32> %call.tmp2, i32 %call.tmp4, i32 2
- %call.old = extractelement <3 x i32> %call.tmp5, i32 0
- ret void
-}
-
-; Function Attrs: nounwind
-declare spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1)*) #0
-
-; Function Attrs: nounwind
-declare spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1)*) #0
-
-attributes #0 = { nounwind }
-
-!opencl.kernels = !{!0}
-!opencl.enable.FP_CONTRACT = !{}
-!spirv.Source = !{!6}
-!opencl.spir.version = !{!7}
-!opencl.ocl.version = !{!7}
-!opencl.used.extensions = !{!8}
-!opencl.used.optional.core.features = !{!9}
-!spirv.Generator = !{!10}
-
-!0 = !{void (%opencl.image2d_array_ro_t addrspace(1)*)* @sample_kernel, !1, !2, !3, !4, !5}
-!1 = !{!"kernel_arg_addr_space", i32 1}
-!2 = !{!"kernel_arg_access_qual", !"read_only"}
-!3 = !{!"kernel_arg_type", !"image2d_array_ro_t"}
-!4 = !{!"kernel_arg_type_qual", !""}
-!5 = !{!"kernel_arg_base_type", !"image2d_array_ro_t"}
-!6 = !{i32 3, i32 102000}
-!7 = !{i32 1, i32 2}
-!8 = !{}
-!9 = !{!"cl_images"}
-!10 = !{i16 6, i16 14}
+; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv -r -spirv-gen-image-type-acc-postfix %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-LLVM: opencl.image2d_array_ro_t = type opaque +; CHECK-LLVM: define spir_kernel void @sample_kernel(%opencl.image2d_array_ro_t addrspace(1) +; CHECK-LLVM-SAME: !kernel_arg_access_qual [[AQ:![0-9]+]] +; CHECK-LLVM-SAME: !kernel_arg_type [[TYPE:![0-9]+]] +; CHECK-LLVM-SAME: !kernel_arg_base_type [[BT:![0-9]+]] + +; CHECK-LLVM: call spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1) +; CHECK-LLVM: call spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1) +; CHECK-LLVM: declare spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1) +; CHECK-LLVM: declare spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1) + +; CHECK-LLVM-DAG: [[AQ]] = !{!"read_only"} +; CHECK-LLVM-DAG: [[TYPE]] = !{!"image2d_array_ro_t"} +; CHECK-LLVM-DAG: [[BT]] = !{!"image2d_array_ro_t"} + +; ModuleID = 'out.ll' +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir64-unknown-unknown" + +%opencl.image2d_array_ro_t = type opaque + +; Function Attrs: nounwind +define spir_kernel void @sample_kernel(%opencl.image2d_array_ro_t addrspace(1)* %input) #0 { +entry: + %call.tmp1 = call spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1)* %input) + %call.tmp2 = shufflevector <2 x i32> %call.tmp1, <2 x i32> undef, <3 x i32> <i32 0, i32 1, i32 2> + %call.tmp3 = call spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1)* %input) + %call.tmp4 = trunc i64 %call.tmp3 to i32 + %call.tmp5 = insertelement <3 x i32> %call.tmp2, i32 %call.tmp4, i32 2 + %call.old = extractelement <3 x i32> %call.tmp5, i32 0 + ret void +} + +; Function Attrs: nounwind +declare spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1)*) #0 + +; Function Attrs: nounwind +declare spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_ro_t(%opencl.image2d_array_ro_t addrspace(1)*) #0 + +attributes #0 = { nounwind } + +!opencl.kernels = !{!0} +!opencl.enable.FP_CONTRACT = !{} +!spirv.Source = !{!6} +!opencl.spir.version = !{!7} +!opencl.ocl.version = !{!7} +!opencl.used.extensions = !{!8} +!opencl.used.optional.core.features = !{!9} +!spirv.Generator = !{!10} + +!0 = !{void (%opencl.image2d_array_ro_t addrspace(1)*)* @sample_kernel, !1, !2, !3, !4, !5} +!1 = !{!"kernel_arg_addr_space", i32 1} +!2 = !{!"kernel_arg_access_qual", !"read_only"} +!3 = !{!"kernel_arg_type", !"image2d_array_ro_t"} +!4 = !{!"kernel_arg_type_qual", !""} +!5 = !{!"kernel_arg_base_type", !"image2d_array_ro_t"} +!6 = !{i32 3, i32 102000} +!7 = !{i32 1, i32 2} +!8 = !{} +!9 = !{!"cl_images"} +!10 = !{i16 6, i16 14} diff --git a/test/transcoding/check_wo_qualifier.ll b/test/transcoding/check_wo_qualifier.ll index 217070e..4388205 100644 --- a/test/transcoding/check_wo_qualifier.ll +++ b/test/transcoding/check_wo_qualifier.ll @@ -1,65 +1,65 @@ -; RUN: llvm-as %s -o %t.bc
-; RUN: llvm-spirv %t.bc -o %t.spv
-; RUN: llvm-spirv -r -spirv-gen-image-type-acc-postfix %t.spv -o %t.rev.bc
-; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-LLVM: opencl.image2d_array_wo_t = type opaque
-; CHECK-LLVM: define spir_kernel void @sample_kernel(%opencl.image2d_array_wo_t addrspace(1)
-; CHECK-LLVM-SAME: !kernel_arg_access_qual [[AQ:![0-9]+]]
-; CHECK-LLVM-SAME: !kernel_arg_type [[TYPE:![0-9]+]]
-; CHECK-LLVM-SAME: !kernel_arg_base_type [[BT:![0-9]+]]
-
-; CHECK-LLVM: call spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1)
-; CHECK-LLVM: call spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1)
-; CHECK-LLVM: declare spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1)
-; CHECK-LLVM: declare spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1)
-; CHECK-LLVM-DAG: [[AQ]] = !{!"write_only"}
-; CHECK-LLVM-DAG: [[TYPE]] = !{!"image2d_array_wo_t"}
-; CHECK-LLVM-DAG: [[BT]] = !{!"image2d_array_wo_t"}
-
-; ModuleID = 'out.ll'
-target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir64-unknown-unknown"
-
-%opencl.image2d_array_wo_t = type opaque
-
-; Function Attrs: nounwind
-define spir_kernel void @sample_kernel(%opencl.image2d_array_wo_t addrspace(1)* %input) #0 {
-entry:
- %call.tmp1 = call spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1)* %input)
- %call.tmp2 = shufflevector <2 x i32> %call.tmp1, <2 x i32> undef, <3 x i32> <i32 0, i32 1, i32 2>
- %call.tmp3 = call spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1)* %input)
- %call.tmp4 = trunc i64 %call.tmp3 to i32
- %call.tmp5 = insertelement <3 x i32> %call.tmp2, i32 %call.tmp4, i32 2
- %call.old = extractelement <3 x i32> %call.tmp5, i32 0
- ret void
-}
-
-; Function Attrs: nounwind
-declare spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1)*) #0
-
-; Function Attrs: nounwind
-declare spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1)*) #0
-
-attributes #0 = { nounwind }
-
-!opencl.kernels = !{!0}
-!opencl.enable.FP_CONTRACT = !{}
-!spirv.Source = !{!6}
-!opencl.spir.version = !{!7}
-!opencl.ocl.version = !{!7}
-!opencl.used.extensions = !{!8}
-!opencl.used.optional.core.features = !{!9}
-!spirv.Generator = !{!10}
-
-!0 = !{void (%opencl.image2d_array_wo_t addrspace(1)*)* @sample_kernel, !1, !2, !3, !4, !5}
-!1 = !{!"kernel_arg_addr_space", i32 1}
-!2 = !{!"kernel_arg_access_qual", !"write_only"}
-!3 = !{!"kernel_arg_type", !"image2d_array_wo_t"}
-!4 = !{!"kernel_arg_type_qual", !""}
-!5 = !{!"kernel_arg_base_type", !"image2d_array_wo_t"}
-!6 = !{i32 3, i32 102000}
-!7 = !{i32 1, i32 2}
-!8 = !{}
-!9 = !{!"cl_images"}
-!10 = !{i16 6, i16 14}
+; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv -r -spirv-gen-image-type-acc-postfix %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-LLVM: opencl.image2d_array_wo_t = type opaque +; CHECK-LLVM: define spir_kernel void @sample_kernel(%opencl.image2d_array_wo_t addrspace(1) +; CHECK-LLVM-SAME: !kernel_arg_access_qual [[AQ:![0-9]+]] +; CHECK-LLVM-SAME: !kernel_arg_type [[TYPE:![0-9]+]] +; CHECK-LLVM-SAME: !kernel_arg_base_type [[BT:![0-9]+]] + +; CHECK-LLVM: call spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1) +; CHECK-LLVM: call spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1) +; CHECK-LLVM: declare spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1) +; CHECK-LLVM: declare spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1) +; CHECK-LLVM-DAG: [[AQ]] = !{!"write_only"} +; CHECK-LLVM-DAG: [[TYPE]] = !{!"image2d_array_wo_t"} +; CHECK-LLVM-DAG: [[BT]] = !{!"image2d_array_wo_t"} + +; ModuleID = 'out.ll' +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir64-unknown-unknown" + +%opencl.image2d_array_wo_t = type opaque + +; Function Attrs: nounwind +define spir_kernel void @sample_kernel(%opencl.image2d_array_wo_t addrspace(1)* %input) #0 { +entry: + %call.tmp1 = call spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1)* %input) + %call.tmp2 = shufflevector <2 x i32> %call.tmp1, <2 x i32> undef, <3 x i32> <i32 0, i32 1, i32 2> + %call.tmp3 = call spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1)* %input) + %call.tmp4 = trunc i64 %call.tmp3 to i32 + %call.tmp5 = insertelement <3 x i32> %call.tmp2, i32 %call.tmp4, i32 2 + %call.old = extractelement <3 x i32> %call.tmp5, i32 0 + ret void +} + +; Function Attrs: nounwind +declare spir_func <2 x i32> @_Z13get_image_dimPU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1)*) #0 + +; Function Attrs: nounwind +declare spir_func i64 @_Z20get_image_array_sizePU3AS125opencl.image2d_array_wo_t(%opencl.image2d_array_wo_t addrspace(1)*) #0 + +attributes #0 = { nounwind } + +!opencl.kernels = !{!0} +!opencl.enable.FP_CONTRACT = !{} +!spirv.Source = !{!6} +!opencl.spir.version = !{!7} +!opencl.ocl.version = !{!7} +!opencl.used.extensions = !{!8} +!opencl.used.optional.core.features = !{!9} +!spirv.Generator = !{!10} + +!0 = !{void (%opencl.image2d_array_wo_t addrspace(1)*)* @sample_kernel, !1, !2, !3, !4, !5} +!1 = !{!"kernel_arg_addr_space", i32 1} +!2 = !{!"kernel_arg_access_qual", !"write_only"} +!3 = !{!"kernel_arg_type", !"image2d_array_wo_t"} +!4 = !{!"kernel_arg_type_qual", !""} +!5 = !{!"kernel_arg_base_type", !"image2d_array_wo_t"} +!6 = !{i32 3, i32 102000} +!7 = !{i32 1, i32 2} +!8 = !{} +!9 = !{!"cl_images"} +!10 = !{i16 6, i16 14} diff --git a/test/unreachable.ll b/test/unreachable.ll index 608ea99..60b9db8 100644 --- a/test/unreachable.ll +++ b/test/unreachable.ll @@ -1,56 +1,56 @@ -; RUN: llvm-as %s -o %t.bc
-; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt
-; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
-; RUN: llvm-spirv %t.bc -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.bc
-; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-SPIRV: 1 Unreachable
-; CHECK-LLVM: unreachable
-
-; ModuleID = 'main'
-target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
-target triple = "spir64-unknown-unknown"
-
-; Function Attrs: nounwind
-define spir_kernel void @unreachable_simple(i32 addrspace(1)* nocapture %in, i32 addrspace(1)* %out) #0 {
- %1 = call spir_func i64 @_Z13get_global_idj(i32 0) #1
- %2 = shl i64 %1, 32
- %3 = ashr exact i64 %2, 32
- %4 = getelementptr inbounds i32, i32 addrspace(1)* %in, i64 %3
- %5 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 %3
- br label %7
- ; No predecessors!
- unreachable
-
-; <label>:7 ; preds = %0
- %8 = load i32, i32 addrspace(1)* %4
- store i32 %8, i32 addrspace(1)* %5
- ret void
-}
-
-; Function Attrs: nounwind readnone
-declare spir_func i64 @_Z13get_global_idj(i32) #1
-
-attributes #0 = { nounwind }
-attributes #1 = { nounwind readnone }
-
-!opencl.kernels = !{!0}
-!opencl.enable.FP_CONTRACT = !{}
-!spirv.Source = !{!6}
-!opencl.spir.version = !{!7}
-!opencl.ocl.version = !{!7}
-!opencl.used.extensions = !{!8}
-!opencl.used.optional.core.features = !{!8}
-!spirv.Generator = !{!9}
-
-!0 = !{void (i32 addrspace(1)*, i32 addrspace(1)*)* @unreachable_simple, !1, !2, !3, !4, !5}
-!1 = !{!"kernel_arg_addr_space", i32 1, i32 1}
-!2 = !{!"kernel_arg_access_qual", !"none", !"none"}
-!3 = !{!"kernel_arg_type", !"int*", !"int*"}
-!4 = !{!"kernel_arg_type_qual", !"", !""}
-!5 = !{!"kernel_arg_base_type", !"int*", !"int*"}
-!6 = !{i32 3, i32 102000}
-!7 = !{i32 1, i32 2}
-!8 = !{}
-!9 = !{i16 7, i16 0}
+; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt +; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.bc +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-SPIRV: 1 Unreachable +; CHECK-LLVM: unreachable + +; ModuleID = 'main' +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir64-unknown-unknown" + +; Function Attrs: nounwind +define spir_kernel void @unreachable_simple(i32 addrspace(1)* nocapture %in, i32 addrspace(1)* %out) #0 { + %1 = call spir_func i64 @_Z13get_global_idj(i32 0) #1 + %2 = shl i64 %1, 32 + %3 = ashr exact i64 %2, 32 + %4 = getelementptr inbounds i32, i32 addrspace(1)* %in, i64 %3 + %5 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 %3 + br label %7 + ; No predecessors! + unreachable + +; <label>:7 ; preds = %0 + %8 = load i32, i32 addrspace(1)* %4 + store i32 %8, i32 addrspace(1)* %5 + ret void +} + +; Function Attrs: nounwind readnone +declare spir_func i64 @_Z13get_global_idj(i32) #1 + +attributes #0 = { nounwind } +attributes #1 = { nounwind readnone } + +!opencl.kernels = !{!0} +!opencl.enable.FP_CONTRACT = !{} +!spirv.Source = !{!6} +!opencl.spir.version = !{!7} +!opencl.ocl.version = !{!7} +!opencl.used.extensions = !{!8} +!opencl.used.optional.core.features = !{!8} +!spirv.Generator = !{!9} + +!0 = !{void (i32 addrspace(1)*, i32 addrspace(1)*)* @unreachable_simple, !1, !2, !3, !4, !5} +!1 = !{!"kernel_arg_addr_space", i32 1, i32 1} +!2 = !{!"kernel_arg_access_qual", !"none", !"none"} +!3 = !{!"kernel_arg_type", !"int*", !"int*"} +!4 = !{!"kernel_arg_type_qual", !"", !""} +!5 = !{!"kernel_arg_base_type", !"int*", !"int*"} +!6 = !{i32 3, i32 102000} +!7 = !{i32 1, i32 2} +!8 = !{} +!9 = !{i16 7, i16 0} diff --git a/test/vector_times_scalar.spt b/test/vector_times_scalar.spt index b6ad4f5..21f5dfe 100644 --- a/test/vector_times_scalar.spt +++ b/test/vector_times_scalar.spt @@ -1,61 +1,61 @@ -119734787 65536 458752 28 0
-2 Capability Addresses
-2 Capability Linkage
-2 Capability Kernel
-2 Capability Float64
-3 MemoryModel 2 2
-8 EntryPoint 6 1 "vector_times_scalar"
-3 Source 3 102000
-3 Name 2 "res"
-3 Name 3 "lhs"
-3 Name 4 "rhs"
-4 Decorate 5 FuncParamAttr 5
-2 DecorationGroup 5
-4 Decorate 6 BuiltIn 28
-3 Decorate 6 Constant
-11 Decorate 6 LinkageAttributes "__spirv_GlobalInvocationId" Import
-5 GroupDecorate 5 2 3 4
-4 TypeInt 7 64 0
-5 Constant 7 10 32 0
-4 TypeVector 8 7 3
-4 TypePointer 9 0 8
-2 TypeVoid 11
-3 TypeFloat 12 64
-4 TypePointer 13 5 12
-4 TypeVector 14 12 4
-4 TypePointer 15 5 14
-6 TypeFunction 16 11 15 15 13
-4 Variable 9 6 0
-
-5 Function 11 1 0 16
-3 FunctionParameter 15 2
-3 FunctionParameter 15 3
-3 FunctionParameter 13 4
-
-2 Label 17
-6 Load 8 18 6 2 0
-5 CompositeExtract 7 19 18 0
-5 ShiftLeftLogical 7 20 19 10
-5 ShiftRightArithmetic 7 21 20 10
-5 InBoundsPtrAccessChain 15 22 3 21
-6 Load 14 23 22 2 32
-5 InBoundsPtrAccessChain 13 24 4 21
-6 Load 12 25 24 2 8
-5 VectorTimesScalar 14 26 23 25
-5 InBoundsPtrAccessChain 15 27 2 21
-5 Store 27 26 2 32
-1 Return
-
-1 FunctionEnd
-
-; FIXME: LIT comments/commands are moved at the end because llvm-spirv stops
-; reading the file after first ';' symbol
-
-; RUN: llvm-spirv %s -to-binary -o %t.spv
-; RUN: llvm-spirv -r %t.spv -o %t.bc
-; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM
-
-; CHECK-LLVM: %.splatinsert = insertelement <4 x double> undef, double %{{[0-9]*}}, i32 0
-; CHECK-LLVM: %[[shufflevector:[0-9]+]] = shufflevector <4 x double> %.splatinsert, <4 x double> undef, <4 x i32> zeroinitializer
-; CHECK-LLVM: %scale = fmul <4 x double> %{{[0-9]*}}, %[[shufflevector]]
-
+119734787 65536 458752 28 0 +2 Capability Addresses +2 Capability Linkage +2 Capability Kernel +2 Capability Float64 +3 MemoryModel 2 2 +8 EntryPoint 6 1 "vector_times_scalar" +3 Source 3 102000 +3 Name 2 "res" +3 Name 3 "lhs" +3 Name 4 "rhs" +4 Decorate 5 FuncParamAttr 5 +2 DecorationGroup 5 +4 Decorate 6 BuiltIn 28 +3 Decorate 6 Constant +11 Decorate 6 LinkageAttributes "__spirv_GlobalInvocationId" Import +5 GroupDecorate 5 2 3 4 +4 TypeInt 7 64 0 +5 Constant 7 10 32 0 +4 TypeVector 8 7 3 +4 TypePointer 9 0 8 +2 TypeVoid 11 +3 TypeFloat 12 64 +4 TypePointer 13 5 12 +4 TypeVector 14 12 4 +4 TypePointer 15 5 14 +6 TypeFunction 16 11 15 15 13 +4 Variable 9 6 0 + +5 Function 11 1 0 16 +3 FunctionParameter 15 2 +3 FunctionParameter 15 3 +3 FunctionParameter 13 4 + +2 Label 17 +6 Load 8 18 6 2 0 +5 CompositeExtract 7 19 18 0 +5 ShiftLeftLogical 7 20 19 10 +5 ShiftRightArithmetic 7 21 20 10 +5 InBoundsPtrAccessChain 15 22 3 21 +6 Load 14 23 22 2 32 +5 InBoundsPtrAccessChain 13 24 4 21 +6 Load 12 25 24 2 8 +5 VectorTimesScalar 14 26 23 25 +5 InBoundsPtrAccessChain 15 27 2 21 +5 Store 27 26 2 32 +1 Return + +1 FunctionEnd + +; FIXME: LIT comments/commands are moved at the end because llvm-spirv stops +; reading the file after first ';' symbol + +; RUN: llvm-spirv %s -to-binary -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.bc +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-LLVM: %.splatinsert = insertelement <4 x double> undef, double %{{[0-9]*}}, i32 0 +; CHECK-LLVM: %[[shufflevector:[0-9]+]] = shufflevector <4 x double> %.splatinsert, <4 x double> undef, <4 x i32> zeroinitializer +; CHECK-LLVM: %scale = fmul <4 x double> %{{[0-9]*}}, %[[shufflevector]] + diff --git a/tools/llvm-spirv/LLVMBuild.txt b/tools/llvm-spirv/LLVMBuild.txt index 49771ea..4accaea 100644 --- a/tools/llvm-spirv/LLVMBuild.txt +++ b/tools/llvm-spirv/LLVMBuild.txt @@ -1,22 +1,22 @@ -;===- ./tools/llvm-bil/LLVMBuild.txt ----------------------------*- Conf -*--===;
-;
-; The LLVM Compiler Infrastructure
-;
-; This file is distributed under the University of Illinois Open Source
-; License. See LICENSE.TXT for details.
-;
-;===------------------------------------------------------------------------===;
-;
-; This is an LLVMBuild description file for the components in this subdirectory.
-;
-; For more information on the LLVMBuild system, please see:
-;
-; http://llvm.org/docs/LLVMBuild.html
-;
-;===------------------------------------------------------------------------===;
-
-[component_0]
-type = Tool
-name = llvm-spirv
-parent = Tools
-required_libraries = Analysis BitReader BitWriter SPIRVLib IPO
+;===- ./tools/llvm-bil/LLVMBuild.txt ----------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = llvm-spirv +parent = Tools +required_libraries = Analysis BitReader BitWriter SPIRVLib IPO diff --git a/tools/llvm-spirv/Makefile b/tools/llvm-spirv/Makefile index 20106cd..039e76f 100644 --- a/tools/llvm-spirv/Makefile +++ b/tools/llvm-spirv/Makefile @@ -1,17 +1,17 @@ -##===- tools/llvm-as/Makefile ------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL := ../..
-TOOLNAME := llvm-spirv
-LINK_COMPONENTS := analysis bitwriter bitreader spirv
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS := 1
-
-include $(LEVEL)/Makefile.common
+##===- tools/llvm-as/Makefile ------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../.. +TOOLNAME := llvm-spirv +LINK_COMPONENTS := analysis bitwriter bitreader spirv + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS := 1 + +include $(LEVEL)/Makefile.common diff --git a/tools/llvm-spirv/llvm-spirv.cpp b/tools/llvm-spirv/llvm-spirv.cpp index 384756f..febd46b 100644 --- a/tools/llvm-spirv/llvm-spirv.cpp +++ b/tools/llvm-spirv/llvm-spirv.cpp @@ -1,301 +1,301 @@ -//===-- llvm-spirv.cpp - The LLVM/SPIR-V translator utility -----*- C++ -*-===//
-//
-//
-// The LLVM/SPIRV Translator
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-// 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.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// Common Usage:
-/// llvm-spirv - Read LLVM bitcode from stdin, write SPIRV to stdout
-/// llvm-spirv x.bc - Read LLVM bitcode from the x.bc file, write SPIR-V
-/// to x.bil file
-/// llvm-spirv -r - Read SPIRV from stdin, write LLVM bitcode to stdout
-/// llvm-spirv -r x.bil - Read SPIRV from the x.bil file, write SPIR-V to
-/// the x.bc file
-///
-/// Options:
-/// --help - Output command line options
-///
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Bitcode/BitcodeReader.h"
-#include "llvm/Bitcode/BitcodeWriter.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Signals.h"
-#include "llvm/Support/ToolOutputFile.h"
-
-#ifndef _SPIRV_SUPPORT_TEXT_FMT
-#define _SPIRV_SUPPORT_TEXT_FMT
-#endif
-
-#include "SPIRV.h"
-
-#include <memory>
-#include <fstream>
-#include <iostream>
-
-#define DEBUG_TYPE "spirv"
-
-namespace kExt {
- const char SpirvBinary[] = ".spv";
- const char SpirvText[] = ".spt";
- const char LLVMBinary[] = ".bc";
-}
-
-using namespace llvm;
-
-static cl::opt<std::string>
-InputFile(cl::Positional, cl::desc("<input file>"), cl::init("-"));
-
-static cl::opt<std::string>
-OutputFile("o", cl::desc("Override output filename"),
- cl::value_desc("filename"));
-
-static cl::opt<bool>
-IsReverse("r", cl::desc("Reverse translation (SPIR-V to LLVM)"));
-
-static cl::opt<bool>
-IsRegularization("s", cl::desc(
- "Regularize LLVM to be representable by SPIR-V"));
-
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
-namespace SPIRV {
-// Use textual format for SPIRV.
-extern bool SPIRVUseTextFormat;
-}
-
-static cl::opt<bool>
-ToText("to-text", cl::desc("Convert input SPIR-V binary to internal textual format"));
-
-static cl::opt<bool>
-ToBinary("to-binary",
- cl::desc("Convert input SPIR-V in internal textual format to binary"));
-#endif
-
-static std::string
-removeExt(const std::string& FileName) {
- size_t Pos = FileName.find_last_of(".");
- if (Pos != std::string::npos)
- return FileName.substr(0, Pos);
- return FileName;
-}
-
-static ExitOnError ExitOnErr;
-
-static int
-convertLLVMToSPIRV() {
- LLVMContext Context;
-
- std::unique_ptr<MemoryBuffer> MB =
- ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(InputFile)));
- std::unique_ptr<Module> M =
- ExitOnErr(getOwningLazyBitcodeModule(std::move(MB), Context,
- /*ShouldLazyLoadMetadata=*/true));
- ExitOnErr(M->materializeAll());
-
- if (OutputFile.empty()) {
- if (InputFile == "-")
- OutputFile = "-";
- else
- OutputFile = removeExt(InputFile) +
- (SPIRV::SPIRVUseTextFormat ? kExt::SpirvText : kExt::SpirvBinary);
- }
-
- llvm::StringRef outFile(OutputFile);
- std::error_code EC;
- std::string Err;
- llvm::raw_fd_ostream OFS(outFile, EC, llvm::sys::fs::F_None);
- if (!WriteSPIRV(M.get(), OFS, Err)) {
- errs() << "Fails to save LLVM as SPIRV: " << Err << '\n';
- return -1;
- }
- return 0;
-}
-
-static int
-convertSPIRVToLLVM() {
- LLVMContext Context;
- std::ifstream IFS(InputFile, std::ios::binary);
- Module *M;
- std::string Err;
-
- if (!ReadSPIRV(Context, IFS, M, Err)) {
- errs() << "Fails to load SPIRV as LLVM Module: " << Err << '\n';
- return -1;
- }
-
- DEBUG(dbgs() << "Converted LLVM module:\n" << *M);
-
-
- raw_string_ostream ErrorOS(Err);
- if (verifyModule(*M, &ErrorOS)){
- errs() << "Fails to verify module: " << ErrorOS.str();
- return -1;
- }
-
- if (OutputFile.empty()) {
- if (InputFile == "-")
- OutputFile = "-";
- else
- OutputFile = removeExt(InputFile) + kExt::LLVMBinary;
- }
-
- std::error_code EC;
- ToolOutputFile Out(OutputFile.c_str(), EC, sys::fs::F_None);
- if (EC) {
- errs() << "Fails to open output file: " << EC.message();
- return -1;
- }
-
- WriteBitcodeToFile(*M, Out.os());
- Out.keep();
- delete M;
- return 0;
-}
-
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
-static int
-convertSPIRV() {
- if (ToBinary == ToText) {
- errs() << "Invalid arguments\n";
- return -1;
- }
- std::ifstream IFS(InputFile, std::ios::binary);
-
- if (OutputFile.empty()) {
- if (InputFile == "-")
- OutputFile = "-";
- else {
- OutputFile = removeExt(InputFile)
- + (ToBinary?kExt::SpirvBinary:kExt::SpirvText);
- }
- }
-
- auto Action = [&](llvm::raw_ostream &OFS) {
- std::string Err;
- if (!SPIRV::ConvertSPIRV(IFS, OFS, Err, ToBinary, ToText)) {
- errs() << "Fails to convert SPIR-V : " << Err << '\n';
- return -1;
- }
- return 0;
- };
- if (OutputFile != "-") {
- std::error_code EC;
- llvm::raw_fd_ostream OFS(llvm::StringRef(OutputFile), EC, llvm::sys::fs::F_None);
- return Action(OFS);
- } else
- return Action(outs());
-}
-#endif
-
-static int
-regularizeLLVM() {
- LLVMContext Context;
-
- std::unique_ptr<MemoryBuffer> MB =
- ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(InputFile)));
- std::unique_ptr<Module> M =
- ExitOnErr(getOwningLazyBitcodeModule(std::move(MB), Context,
- /*ShouldLazyLoadMetadata=*/true));
- ExitOnErr(M->materializeAll());
-
- if (OutputFile.empty()) {
- if (InputFile == "-")
- OutputFile = "-";
- else
- OutputFile = removeExt(InputFile) + ".regularized.bc";
- }
-
- std::string Err;
- if (!RegularizeLLVMForSPIRV(M.get(), Err)) {
- errs() << "Fails to save LLVM as SPIRV: " << Err << '\n';
- return -1;
- }
-
- std::error_code EC;
- ToolOutputFile Out(OutputFile.c_str(), EC, sys::fs::F_None);
- if (EC) {
- errs() << "Fails to open output file: " << EC.message();
- return -1;
- }
-
- WriteBitcodeToFile(*M.get(), Out.os());
- Out.keep();
- return 0;
-}
-
-
-int
-main(int ac, char** av) {
- EnablePrettyStackTrace();
- sys::PrintStackTraceOnErrorSignal(av[0]);
- PrettyStackTraceProgram X(ac, av);
-
- cl::ParseCommandLineOptions(ac, av, "LLVM/SPIR-V translator");
-
-#ifdef _SPIRV_SUPPORT_TEXT_FMT
- if (ToText && (ToBinary || IsReverse || IsRegularization)) {
- errs() << "Cannot use -to-text with -to-binary, -r, -s\n";
- return -1;
- }
-
- if (ToBinary && (ToText || IsReverse || IsRegularization)) {
- errs() << "Cannot use -to-binary with -to-text, -r, -s\n";
- return -1;
- }
-
- if (ToBinary || ToText)
- return convertSPIRV();
-#endif
-
- if (!IsReverse && !IsRegularization)
- return convertLLVMToSPIRV();
-
- if (IsReverse && IsRegularization) {
- errs() << "Cannot have both -r and -s options\n";
- return -1;
- }
- if (IsReverse)
- return convertSPIRVToLLVM();
-
- if (IsRegularization)
- return regularizeLLVM();
-
- return 0;
-}
+//===-- llvm-spirv.cpp - The LLVM/SPIR-V translator utility -----*- C++ -*-===// +// +// +// The LLVM/SPIRV Translator +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// 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. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// Common Usage: +/// llvm-spirv - Read LLVM bitcode from stdin, write SPIRV to stdout +/// llvm-spirv x.bc - Read LLVM bitcode from the x.bc file, write SPIR-V +/// to x.bil file +/// llvm-spirv -r - Read SPIRV from stdin, write LLVM bitcode to stdout +/// llvm-spirv -r x.bil - Read SPIRV from the x.bil file, write SPIR-V to +/// the x.bc file +/// +/// Options: +/// --help - Output command line options +/// +//===----------------------------------------------------------------------===// + +#include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/ToolOutputFile.h" + +#ifndef _SPIRV_SUPPORT_TEXT_FMT +#define _SPIRV_SUPPORT_TEXT_FMT +#endif + +#include "SPIRV.h" + +#include <memory> +#include <fstream> +#include <iostream> + +#define DEBUG_TYPE "spirv" + +namespace kExt { + const char SpirvBinary[] = ".spv"; + const char SpirvText[] = ".spt"; + const char LLVMBinary[] = ".bc"; +} + +using namespace llvm; + +static cl::opt<std::string> +InputFile(cl::Positional, cl::desc("<input file>"), cl::init("-")); + +static cl::opt<std::string> +OutputFile("o", cl::desc("Override output filename"), + cl::value_desc("filename")); + +static cl::opt<bool> +IsReverse("r", cl::desc("Reverse translation (SPIR-V to LLVM)")); + +static cl::opt<bool> +IsRegularization("s", cl::desc( + "Regularize LLVM to be representable by SPIR-V")); + +#ifdef _SPIRV_SUPPORT_TEXT_FMT +namespace SPIRV { +// Use textual format for SPIRV. +extern bool SPIRVUseTextFormat; +} + +static cl::opt<bool> +ToText("to-text", cl::desc("Convert input SPIR-V binary to internal textual format")); + +static cl::opt<bool> +ToBinary("to-binary", + cl::desc("Convert input SPIR-V in internal textual format to binary")); +#endif + +static std::string +removeExt(const std::string& FileName) { + size_t Pos = FileName.find_last_of("."); + if (Pos != std::string::npos) + return FileName.substr(0, Pos); + return FileName; +} + +static ExitOnError ExitOnErr; + +static int +convertLLVMToSPIRV() { + LLVMContext Context; + + std::unique_ptr<MemoryBuffer> MB = + ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(InputFile))); + std::unique_ptr<Module> M = + ExitOnErr(getOwningLazyBitcodeModule(std::move(MB), Context, + /*ShouldLazyLoadMetadata=*/true)); + ExitOnErr(M->materializeAll()); + + if (OutputFile.empty()) { + if (InputFile == "-") + OutputFile = "-"; + else + OutputFile = removeExt(InputFile) + + (SPIRV::SPIRVUseTextFormat ? kExt::SpirvText : kExt::SpirvBinary); + } + + llvm::StringRef outFile(OutputFile); + std::error_code EC; + std::string Err; + llvm::raw_fd_ostream OFS(outFile, EC, llvm::sys::fs::F_None); + if (!WriteSPIRV(M.get(), OFS, Err)) { + errs() << "Fails to save LLVM as SPIRV: " << Err << '\n'; + return -1; + } + return 0; +} + +static int +convertSPIRVToLLVM() { + LLVMContext Context; + std::ifstream IFS(InputFile, std::ios::binary); + Module *M; + std::string Err; + + if (!ReadSPIRV(Context, IFS, M, Err)) { + errs() << "Fails to load SPIRV as LLVM Module: " << Err << '\n'; + return -1; + } + + DEBUG(dbgs() << "Converted LLVM module:\n" << *M); + + + raw_string_ostream ErrorOS(Err); + if (verifyModule(*M, &ErrorOS)){ + errs() << "Fails to verify module: " << ErrorOS.str(); + return -1; + } + + if (OutputFile.empty()) { + if (InputFile == "-") + OutputFile = "-"; + else + OutputFile = removeExt(InputFile) + kExt::LLVMBinary; + } + + std::error_code EC; + ToolOutputFile Out(OutputFile.c_str(), EC, sys::fs::F_None); + if (EC) { + errs() << "Fails to open output file: " << EC.message(); + return -1; + } + + WriteBitcodeToFile(*M, Out.os()); + Out.keep(); + delete M; + return 0; +} + +#ifdef _SPIRV_SUPPORT_TEXT_FMT +static int +convertSPIRV() { + if (ToBinary == ToText) { + errs() << "Invalid arguments\n"; + return -1; + } + std::ifstream IFS(InputFile, std::ios::binary); + + if (OutputFile.empty()) { + if (InputFile == "-") + OutputFile = "-"; + else { + OutputFile = removeExt(InputFile) + + (ToBinary?kExt::SpirvBinary:kExt::SpirvText); + } + } + + auto Action = [&](llvm::raw_ostream &OFS) { + std::string Err; + if (!SPIRV::ConvertSPIRV(IFS, OFS, Err, ToBinary, ToText)) { + errs() << "Fails to convert SPIR-V : " << Err << '\n'; + return -1; + } + return 0; + }; + if (OutputFile != "-") { + std::error_code EC; + llvm::raw_fd_ostream OFS(llvm::StringRef(OutputFile), EC, llvm::sys::fs::F_None); + return Action(OFS); + } else + return Action(outs()); +} +#endif + +static int +regularizeLLVM() { + LLVMContext Context; + + std::unique_ptr<MemoryBuffer> MB = + ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(InputFile))); + std::unique_ptr<Module> M = + ExitOnErr(getOwningLazyBitcodeModule(std::move(MB), Context, + /*ShouldLazyLoadMetadata=*/true)); + ExitOnErr(M->materializeAll()); + + if (OutputFile.empty()) { + if (InputFile == "-") + OutputFile = "-"; + else + OutputFile = removeExt(InputFile) + ".regularized.bc"; + } + + std::string Err; + if (!RegularizeLLVMForSPIRV(M.get(), Err)) { + errs() << "Fails to save LLVM as SPIRV: " << Err << '\n'; + return -1; + } + + std::error_code EC; + ToolOutputFile Out(OutputFile.c_str(), EC, sys::fs::F_None); + if (EC) { + errs() << "Fails to open output file: " << EC.message(); + return -1; + } + + WriteBitcodeToFile(*M.get(), Out.os()); + Out.keep(); + return 0; +} + + +int +main(int ac, char** av) { + EnablePrettyStackTrace(); + sys::PrintStackTraceOnErrorSignal(av[0]); + PrettyStackTraceProgram X(ac, av); + + cl::ParseCommandLineOptions(ac, av, "LLVM/SPIR-V translator"); + +#ifdef _SPIRV_SUPPORT_TEXT_FMT + if (ToText && (ToBinary || IsReverse || IsRegularization)) { + errs() << "Cannot use -to-text with -to-binary, -r, -s\n"; + return -1; + } + + if (ToBinary && (ToText || IsReverse || IsRegularization)) { + errs() << "Cannot use -to-binary with -to-text, -r, -s\n"; + return -1; + } + + if (ToBinary || ToText) + return convertSPIRV(); +#endif + + if (!IsReverse && !IsRegularization) + return convertLLVMToSPIRV(); + + if (IsReverse && IsRegularization) { + errs() << "Cannot have both -r and -s options\n"; + return -1; + } + if (IsReverse) + return convertSPIRVToLLVM(); + + if (IsRegularization) + return regularizeLLVM(); + + return 0; +} |