summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Moreau <dev@pmoreau.org>2018-04-13 17:38:55 +0200
committerAlexey Sotkin <alexey.sotkin@intel.com>2018-04-24 12:21:49 +0300
commitd1c02b3954cfdeaca99c0b5d17ce55f02c94e792 (patch)
tree86ce820fb95b32701222cee65924f2cb1e72c67f
parent01dddd07c475bcbb24a11931c649384c904e82d8 (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 "*"`
-rw-r--r--include/SPIRV.h322
-rw-r--r--lib/SPIRV/CMakeLists.txt104
-rw-r--r--lib/SPIRV/LLVMBuild.txt46
-rw-r--r--lib/SPIRV/OCL20ToSPIRV.cpp3086
-rw-r--r--lib/SPIRV/SPIRVInternal.h1866
-rw-r--r--lib/SPIRV/SPIRVLowerBool.cpp268
-rw-r--r--lib/SPIRV/SPIRVLowerMemmove.cpp280
-rw-r--r--lib/SPIRV/SPIRVLowerOCLBlocks.cpp1272
-rw-r--r--lib/SPIRV/SPIRVReader.cpp6236
-rw-r--r--lib/SPIRV/SPIRVToOCL20.cpp2
-rw-r--r--lib/SPIRV/SPIRVWriter.cpp3734
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVBasicBlock.cpp170
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVBasicBlock.h228
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVDebug.cpp92
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVDebug.h162
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVDecorate.cpp476
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVDecorate.h642
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVEntry.cpp1304
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVEntry.h1564
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVEnum.h836
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVError.h254
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVExtInst.h550
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVFunction.cpp342
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVFunction.h336
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVInstruction.cpp464
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVInstruction.h4372
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVModule.cpp3342
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVModule.h724
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVOpCode.h356
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h594
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVStream.cpp540
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVStream.h404
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVType.cpp586
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVType.h1520
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVUtil.h854
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVValue.cpp152
-rw-r--r--lib/SPIRV/libSPIRV/SPIRVValue.h814
-rw-r--r--lib/SPIRV/libSPIRV/libSPIRV.h104
-rw-r--r--test/CheckCapKernelWithoutKernel.ll46
-rw-r--r--test/CreatePipeFromPipeStorage.ll338
-rw-r--r--test/ExecutionMode.ll300
-rw-r--r--test/ExecutionMode_SPIR_to_SPIRV.ll104
-rw-r--r--test/FOrdGreaterThanEqual_bool.ll90
-rw-r--r--test/OpLoopMergeDontUnroll.spt180
-rw-r--r--test/OpLoopMergeNone.spt172
-rw-r--r--test/OpLoopMergeUnroll.spt174
-rw-r--r--test/PipeStorage.ll116
-rw-r--r--test/SPIRVVersionAutodetect_1_0.ll62
-rw-r--r--test/SPIRVVersionAutodetect_1_1.ll66
-rw-r--r--test/builtin_vars-decorate.ll192
-rw-r--r--test/composite_construct_struct.spt112
-rw-r--r--test/composite_construct_vector.spt98
-rw-r--r--test/copy_object.spt100
-rw-r--r--test/fmod.ll98
-rw-r--r--test/lifetime.ll146
-rw-r--r--test/linkage-types.ll334
-rw-r--r--test/selection_merge.spt146
-rw-r--r--test/simple.ll316
-rw-r--r--test/transcoding/DecorationMaxByteOffset.ll106
-rw-r--r--test/transcoding/check_ro_qualifier.ll132
-rw-r--r--test/transcoding/check_wo_qualifier.ll130
-rw-r--r--test/unreachable.ll112
-rw-r--r--test/vector_times_scalar.spt122
-rw-r--r--tools/llvm-spirv/LLVMBuild.txt44
-rw-r--r--tools/llvm-spirv/Makefile34
-rw-r--r--tools/llvm-spirv/llvm-spirv.cpp602
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;
+}