Browse Source

[spirv] Add utility functions for encoding and decoding strings (#352)

Ehsan 8 years ago
parent
commit
6ad98439fe

+ 32 - 0
tools/clang/include/clang/SPIRV/String.h

@@ -0,0 +1,32 @@
+//===-- String.h - SPIR-V Strings -------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SPIRV_STRING_H
+#define LLVM_CLANG_SPIRV_STRING_H
+
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace spirv {
+namespace string {
+
+/// \brief Reinterprets a given string as sequence of words. It follows the
+/// SPIR-V string encoding requirements.
+std::vector<uint32_t> encodeSPIRVString(std::string s);
+
+/// \brief Reinterprets the given vector of 32-bit words as a string.
+/// Expectes that the words represent a NULL-terminated string.
+/// It follows the SPIR-V string encoding requirements.
+std::string decodeSPIRVString(std::vector<uint32_t> &vec);
+
+} // end namespace string
+} // end namespace spirv
+} // end namespace clang
+
+#endif

+ 2 - 1
tools/clang/lib/SPIRV/CMakeLists.txt

@@ -5,10 +5,11 @@ set(LLVM_LINK_COMPONENTS
 add_clang_library(clangSPIRV
   EmitSPIRVAction.cpp
   SPIRVBuilder.cpp
+  String.cpp
 
   LINK_LIBS
   clangAST
   clangBasic
   clangFrontend
   clangLex
-  )
+  )

+ 52 - 0
tools/clang/lib/SPIRV/String.cpp

@@ -0,0 +1,52 @@
+//===-- String.cpp - SPIR-V Strings -----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/SPIRV/String.h"
+#include "llvm/llvm_assert/assert.h"
+
+namespace clang {
+namespace spirv {
+namespace string {
+
+/// \brief Reinterprets a given string as sequence of words.
+std::vector<uint32_t> encodeSPIRVString(std::string s) {
+  // Initialize all words to 0.
+  size_t numChars = s.size();
+  std::vector<uint32_t> result(numChars / 4 + 1, 0);
+
+  // From the SPIR-V spec, literal string is
+  //
+  // A nul-terminated stream of characters consuming an integral number of
+  // words. The character set is Unicode in the UTF-8 encoding scheme. The UTF-8
+  // octets (8-bit bytes) are packed four per word, following the little-endian
+  // convention (i.e., the first octet is in the lowest-order 8 bits of the
+  // word). The final word contains the string's nul-termination character (0),
+  // and all contents past the end of the string in the final word are padded
+  // with 0.
+  //
+  // So the following works on little endian machines.
+  char *strDest = reinterpret_cast<char *>(result.data());
+  strncpy(strDest, s.c_str(), numChars);
+  return result;
+}
+
+/// \brief Reinterprets the given vector of 32-bit words as a string.
+/// Expectes that the words represent a NULL-terminated string.
+/// Assumes Little Endian architecture.
+std::string decodeSPIRVString(std::vector<uint32_t>& vec) {
+  std::string result;
+  if (!vec.empty()) {
+    result = std::string(reinterpret_cast<const char*>(vec.data()));
+  }
+  return result;
+}
+
+} // end namespace string
+} // end namespace spirv
+} // end namespace clang

+ 2 - 1
tools/clang/unittests/SPIRV/CMakeLists.txt

@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_clang_unittest(clang-spirv-tests
   TestMain.cpp
+  StringTest.cpp
   )
 
 target_link_libraries(clang-spirv-tests
@@ -14,4 +15,4 @@ target_link_libraries(clang-spirv-tests
   clangSPIRV
   )
 
-set_output_directory(clang-spirv-tests ${LLVM_RUNTIME_OUTPUT_INTDIR} ${LLVM_LIBRARY_OUTPUT_INTDIR})
+set_output_directory(clang-spirv-tests ${LLVM_RUNTIME_OUTPUT_INTDIR} ${LLVM_LIBRARY_OUTPUT_INTDIR})

+ 85 - 0
tools/clang/unittests/SPIRV/StringTest.cpp

@@ -0,0 +1,85 @@
+//===- unittests/SPIRV/StringTest.cpp ---- SPIR-V String tests ------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gmock/gmock.h"
+#include "clang/SPIRV/String.h"
+#include "gtest/gtest.h"
+
+namespace {
+
+using namespace clang::spirv;
+using ::testing::ElementsAre;
+
+TEST(String, EncodeEmptyString) {
+  std::string str = "";
+  std::vector<uint32_t> words = string::encodeSPIRVString(str);
+  EXPECT_THAT(words, ElementsAre(0u));
+}
+TEST(String, EncodeOneCharString) {
+  std::string str = "m";
+  std::vector<uint32_t> words = string::encodeSPIRVString(str);
+  EXPECT_THAT(words, ElementsAre(109u));
+}
+TEST(String, EncodeTwoCharString) {
+  std::string str = "ma";
+  std::vector<uint32_t> words = string::encodeSPIRVString(str);
+  EXPECT_THAT(words, ElementsAre(24941u));
+}
+TEST(String, EncodeThreeCharString) {
+  std::string str = "mai";
+  std::vector<uint32_t> words = string::encodeSPIRVString(str);
+  EXPECT_THAT(words, ElementsAre(6906221u));
+}
+TEST(String, EncodeFourCharString) {
+  std::string str = "main";
+  std::vector<uint32_t> words = string::encodeSPIRVString(str);
+  EXPECT_THAT(words, ElementsAre(1852399981u, 0u));
+}
+TEST(String, EncodeString) {
+  // Bin  01110100   01110011    01100101    01010100 = unsigned(1,953,719,636)
+  // Hex     74         73          65          54
+  //          t          s           e           T
+  // Bin  01101001   01110010    01110100    01010011 =  unsigned(1,769,108,563)
+  // Hex     69         72          74          53
+  //          i          r           t           S
+  // Bin  00000000   00000000    01100111    01101110 =  unsigned(26,478)
+  // Hex      0          0          67          6E
+  //          \0         \0          g           n
+  std::string str = "TestString";
+  std::vector<uint32_t> words = string::encodeSPIRVString(str);
+  EXPECT_THAT(words, ElementsAre(1953719636, 1769108563, 26478));
+}
+TEST(String, DecodeString) {
+  // Bin  01110100   01110011    01100101    01010100 = unsigned(1,953,719,636)
+  // Hex     74         73          65          54
+  //          t          s           e           T
+  // Bin  01101001   01110010    01110100    01010011 =  unsigned(1,769,108,563)
+  // Hex     69         72          74          53
+  //          i          r           t           S
+  // Bin  00000000   00000000    01100111    01101110 =  unsigned(26,478)
+  // Hex      0          0          67          6E
+  //          \0         \0          g           n
+  std::vector<uint32_t> words = {1953719636, 1769108563, 26478};
+  std::string str = string::decodeSPIRVString(words);
+  EXPECT_EQ(str, "TestString");
+}
+TEST(String, EncodeAndDecodeString) {
+  std::string str = "TestString";
+  // Convert to vector
+  std::vector<uint32_t> words = string::encodeSPIRVString(str);
+
+  // Convert back to string
+  std::string result = string::decodeSPIRVString(words);
+
+  EXPECT_EQ(str, result);
+}
+
+// TODO: Add more ModuleBuilder tests
+
+} // anonymous namespace