From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: nrudenko <nikita.rudenko@intel.com>
Date: Thu, 4 Jun 2020 15:20:43 +0300
Subject: [PATCH 2/6] Add SPIRVDLL and VCExport

---
 lib/SPIRV/CMakeLists.txt | 41 +++++++++++++++++-
 lib/SPIRV/VCExport.cpp   | 89 ++++++++++++++++++++++++++++++++++++++++
 lib/SPIRV/VCExport.h     | 28 +++++++++++++
 3 files changed, 157 insertions(+), 1 deletion(-)
 mode change 100644 => 100755 lib/SPIRV/CMakeLists.txt
 create mode 100755 lib/SPIRV/VCExport.cpp
 create mode 100755 lib/SPIRV/VCExport.h

diff --git a/lib/SPIRV/CMakeLists.txt b/lib/SPIRV/CMakeLists.txt
old mode 100644
new mode 100755
index 00000000..00000000
--- a/lib/SPIRV/CMakeLists.txt
+++ b/lib/SPIRV/CMakeLists.txt
@@ -1,4 +1,5 @@
-add_llvm_library(LLVMSPIRVLib
+set(SPIRV_SOURCES
+  VCExport.cpp
   LLVMToSPIRVDbgTran.cpp
   Mangler/FunctionDescriptor.cpp
   Mangler/Mangler.cpp
@@ -34,6 +35,10 @@ add_llvm_library(LLVMSPIRVLib
   libSPIRV/SPIRVStream.cpp
   libSPIRV/SPIRVType.cpp
   libSPIRV/SPIRVValue.cpp
+)
+
+add_llvm_library(LLVMSPIRVLib
+  ${SPIRV_SOURCES}
   LINK_COMPONENTS
     Analysis
     BitWriter
@@ -44,6 +49,31 @@ add_llvm_library(LLVMSPIRVLib
     intrinsics_gen
 )
 
+# --- mock: add_llvm_library(SPIRVDLL MODULE ---
+# unfortunately this do not work for llvm build system as is so some magic below
+
+add_library(SPIRVDLL MODULE
+  ${SPIRV_SOURCES}
+)
+
+llvm_update_compile_flags(SPIRVDLL)
+
+add_dependencies(SPIRVDLL intrinsics_gen LLVMAnalysis LLVMBitWriter LLVMCore LLVMSupport LLVMTransformUtils)
+target_link_libraries(SPIRVDLL LLVMAnalysis LLVMBitWriter LLVMCore LLVMSupport LLVMTransformUtils)
+
+install(TARGETS SPIRVDLL
+        EXPORT LLVMExports
+        LIBRARY DESTINATION lib
+        COMPONENT SPIRVDLL)
+
+add_llvm_install_targets(install-SPIRVDLL
+                         DEPENDS SPIRVDLL
+                         COMPONENT SPIRVDLL)
+
+set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS SPIRVDLL)
+
+# --- end mock ---
+
 target_include_directories(LLVMSPIRVLib
   PRIVATE
     ${LLVM_INCLUDE_DIRS}
@@ -52,3 +82,12 @@ target_include_directories(LLVMSPIRVLib
     ${CMAKE_CURRENT_SOURCE_DIR}/libSPIRV
     ${CMAKE_CURRENT_SOURCE_DIR}/Mangler
 )
+
+target_include_directories(SPIRVDLL
+  PRIVATE
+    ${LLVM_INCLUDE_DIRS}
+    ${LLVM_SPIRV_INCLUDE_DIRS}
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/libSPIRV
+    ${CMAKE_CURRENT_SOURCE_DIR}/Mangler
+)
diff --git a/lib/SPIRV/VCExport.cpp b/lib/SPIRV/VCExport.cpp
new file mode 100755
index 00000000..00000000
--- /dev/null
+++ b/lib/SPIRV/VCExport.cpp
@@ -0,0 +1,89 @@
+//===- VCExport.cpp - dll interface for SPIRV implementation -*- C++ -*----===//
+//
+//                     The LLVM/SPIR-V Translator
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements dll interface of SPIRV translator
+//
+//===----------------------------------------------------------------------===//
+
+#include <algorithm>
+#include <iostream>
+#include <memory>
+#include <utility>
+
+#include "LLVMSPIRVLib.h"
+#include "SPIRVInternal.h"
+#include "VCExport.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+SPIRV::TranslatorOpts GetTranslatorOpts() {
+  std::map<std::string, ExtensionID> ExtensionNamesMap;
+#define _STRINGIFY(X) #X
+#define STRINGIFY(X) _STRINGIFY(X)
+#define EXT(X) ExtensionNamesMap[STRINGIFY(X)] = ExtensionID::X;
+#include "LLVMSPIRVExtensions.inc"
+#undef EXT
+#undef STRINGIFY
+#undef _STRINGIFY
+
+  SPIRV::TranslatorOpts::ExtensionsStatusMap ExtensionsStatus;
+  // Set the initial state:
+  //  - during SPIR-V consumption, assume that any known extension is allowed.
+  //  - during SPIR-V generation, assume that any known extension is disallowed.
+  //  - during conversion to/from SPIR-V text representation, assume that any
+  //    known extension is allowed.
+  for (const auto &It : ExtensionNamesMap)
+    ExtensionsStatus[It.second] = true;
+  SPIRV::TranslatorOpts Opts(VersionNumber::MaximumVersion, ExtensionsStatus);
+  Opts.setFPContractMode(SPIRV::FPContractMode::On);
+  Opts.setDesiredBIsRepresentation(SPIRV::BIsRepresentation::SPIRVFriendlyIR);
+  return Opts;
+}
+
+int spirv_read_verify_module(
+    const char *pIn, size_t InSz,
+    void (*OutSaver)(const char *pOut, size_t OutSize, void *OutUserData),
+    void *OutUserData, void (*ErrSaver)(const char *pErrMsg, void *ErrUserData),
+    void *ErrUserData) {
+  LLVMContext Context;
+  StringRef SpirvInput = StringRef(pIn, InSz);
+  std::istringstream IS(SpirvInput.str());
+
+  std::unique_ptr<llvm::Module> M;
+  {
+    llvm::Module *SpirM;
+    std::string ErrMsg;
+    auto Opts = GetTranslatorOpts();
+    // This returns true on success...
+    bool Status = llvm::readSpirv(Context, Opts, IS, SpirM, ErrMsg);
+    if (!Status) {
+      std::ostringstream OSS;
+      OSS << "spirv_read_verify: readSpirv failed: " << ErrMsg;
+      ErrSaver(OSS.str().c_str(), ErrUserData);
+      return -1;
+    }
+
+    Status = llvm::verifyModule(*SpirM);
+    if (Status) {
+      ErrSaver("spirv_read_verify: verify Module failed", ErrUserData);
+      return -1;
+    }
+
+    M.reset(SpirM);
+  }
+
+  llvm::SmallVector<char, 16> CloneBuffer;
+  llvm::raw_svector_ostream CloneOstream(CloneBuffer);
+  WriteBitcodeToFile(*M, CloneOstream);
+
+  assert(CloneBuffer.size() > 0);
+
+  OutSaver(CloneBuffer.data(), CloneBuffer.size(), OutUserData);
+  return 0;
+}
diff --git a/lib/SPIRV/VCExport.h b/lib/SPIRV/VCExport.h
new file mode 100755
index 00000000..00000000
--- /dev/null
+++ b/lib/SPIRV/VCExport.h
@@ -0,0 +1,28 @@
+//===- VCExport.h - Adding possibility to build spirv as a dll -*- C++ -*-===//
+//
+//                     The LLVM/SPIR-V Translator
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is kind of a temporal solution
+// We need to live in separate DLL while IGC default SPIRV is not ready
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SPIRV_VCEXPORT_H
+#define SPIRV_VCEXPORT_H
+
+#ifdef _WIN32
+#define __EXPORT__ __declspec(dllexport)
+#else
+#define __EXPORT__ __attribute__((visibility("default")))
+#endif
+
+// Returns zero on success.
+extern "C" __EXPORT__ int spirv_read_verify_module(
+    const char *pIn, size_t InSz,
+    void (*OutSaver)(const char *pOut, size_t OutSize, void *OutUserData),
+    void *OutUserData, void (*ErrSaver)(const char *pErrMsg, void *ErrUserData),
+    void *ErrUserData);
+
+#endif // SPIRV_VCEXPORT_H
-- 
2.31.0

