Define RS metadata spec and implement the encoder.

However, it's not enabled in any code currently since decoder doen't implement.
diff --git a/slang_rs_metadata_spec_encoder.cpp b/slang_rs_metadata_spec_encoder.cpp
new file mode 100644
index 0000000..90c26e3
--- /dev/null
+++ b/slang_rs_metadata_spec_encoder.cpp
@@ -0,0 +1,520 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "slang_rs_metadata_spec.h"
+
+#include <map>
+#include <list>
+#include <string>
+#include <cstdlib>
+
+#include "llvm/Module.h"
+#include "llvm/Metadata.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+#include "slang_rs_type_spec.h"
+
+#define RS_METADATA_STRTAB_MN   "#rs_metadata_strtab"
+#define RS_TYPE_INFO_MN         "#rs_type_info"
+#define RS_EXPORT_VAR_MN        "#rs_export_var"
+#define RS_EXPORT_FUNC_MN       "#rs_export_func"
+#define RS_EXPORT_RECORD_TYPE_NAME_MN_PREFIX  "%"
+
+///////////////////////////////////////////////////////////////////////////////
+// Useful utility functions
+///////////////////////////////////////////////////////////////////////////////
+static bool EncodeInteger(llvm::LLVMContext &C,
+                          unsigned I,
+                          llvm::SmallVectorImpl<llvm::Value*> &Op) {
+  llvm::StringRef S(reinterpret_cast<const char*>(&I), sizeof(I));
+  llvm::MDString *MDS = llvm::MDString::get(C, S);
+
+  if (MDS == NULL)
+    return false;
+  Op.push_back(MDS);
+  return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// class RSMetadataEncoderInternal
+///////////////////////////////////////////////////////////////////////////////
+namespace {
+
+class RSMetadataEncoderInternal {
+ private:
+  llvm::Module *mModule;
+
+  typedef std::map</* key */unsigned, unsigned/* index */> TypesMapTy;
+  TypesMapTy mTypes;
+  std::list<unsigned> mEncodedRSTypeInfo;  // simply a sequece of integers
+  unsigned mCurTypeIndex;
+
+  // A special type for lookup created record type. It uses record name as key.
+  typedef std::map</* name */std::string, unsigned/* index */> RecordTypesMapTy;
+  RecordTypesMapTy mRecordTypes;
+
+  typedef std::map<std::string, unsigned/* index */> StringsMapTy;
+  StringsMapTy mStrings;
+  std::list<const char*> mEncodedStrings;
+  unsigned mCurStringIndex;
+
+  llvm::NamedMDNode *mVarInfoMetadata;
+  llvm::NamedMDNode *mFuncInfoMetadata;
+
+  // This function check the return value of function:
+  //   joinString, encodeTypeBase, encode*Type(), encodeRSType, encodeRSVar,
+  //   and encodeRSFunc. Return false if the value of Index indicates failure.
+  inline bool checkReturnIndex(unsigned &Index) {
+    if (Index == 0)
+      return false;
+    else
+      Index--;
+    return true;
+  }
+
+  unsigned joinString(const std::string &S);
+
+  unsigned encodeTypeBase(const struct RSTypeBase *Base);
+  unsigned encodeTypeBaseAsKey(const struct RSTypeBase *Base);
+#define ENUM_RS_DATA_TYPE_CLASS(x)  \
+  unsigned encode ## x ## Type(const union RSType *T);
+RS_DATA_TYPE_CLASS_ENUMS
+#undef ENUM_RS_DATA_TYPE_CLASS
+
+  unsigned encodeRSType(const union RSType *T);
+
+  int flushStringTable();
+  int flushTypeInfo();
+
+ public:
+  RSMetadataEncoderInternal(llvm::Module *M);
+
+  int encodeRSVar(const RSVar *V);
+  int encodeRSFunc(const RSFunction *F);
+
+  int finalize();
+};
+
+}
+
+RSMetadataEncoderInternal::RSMetadataEncoderInternal(llvm::Module *M)
+    : mModule(M),
+      mCurTypeIndex(0),
+      mCurStringIndex(0),
+      mVarInfoMetadata(NULL),
+      mFuncInfoMetadata(NULL) {
+  mTypes.clear();
+  mEncodedRSTypeInfo.clear();
+  mRecordTypes.clear();
+  mStrings.clear();
+
+  return;
+}
+
+// Return (StringIndex + 1) when successfully join the string and 0 if there's
+// any error.
+unsigned RSMetadataEncoderInternal::joinString(const std::string &S) {
+  StringsMapTy::const_iterator I = mStrings.find(S);
+
+  if (I != mStrings.end())
+    return (I->second + 1);
+
+  // Add S into mStrings
+  std::pair<StringsMapTy::iterator, bool> Res =
+      mStrings.insert(std::make_pair(S, mCurStringIndex));
+  // Insertion failed
+  if (!Res.second)
+    return 0;
+
+  // Add S into mEncodedStrings
+  mEncodedStrings.push_back(Res.first->first.c_str());
+  mCurStringIndex++;
+
+  // Return (StringIndex + 1)
+  return (Res.first->second + 1);
+}
+
+unsigned
+RSMetadataEncoderInternal::encodeTypeBase(const struct RSTypeBase *Base) {
+  mEncodedRSTypeInfo.push_back(Base->bits);
+  return ++mCurTypeIndex;
+}
+
+unsigned RSMetadataEncoderInternal::encodeTypeBaseAsKey(
+    const struct RSTypeBase *Base) {
+  TypesMapTy::const_iterator I = mTypes.find(Base->bits);
+  if (I != mTypes.end())
+    return (I->second + 1);
+
+  // Add Base into mTypes
+  std::pair<TypesMapTy::iterator, bool> Res =
+      mTypes.insert(std::make_pair(Base->bits, mCurTypeIndex));
+  // Insertion failed
+  if (!Res.second)
+    return 0;
+
+  // Push to mEncodedRSTypeInfo. This will also update mCurTypeIndex.
+  return encodeTypeBase(Base);
+}
+
+unsigned RSMetadataEncoderInternal::encodePrimitiveType(const union RSType *T) {
+  return encodeTypeBaseAsKey(RS_GET_TYPE_BASE(T));
+}
+
+unsigned RSMetadataEncoderInternal::encodePointerType(const union RSType *T) {
+  // Encode pointee type first
+  unsigned PointeeType = encodeRSType(RS_POINTER_TYPE_GET_POINTEE_TYPE(T));
+  if (!checkReturnIndex(PointeeType))
+    return 0;
+
+  unsigned Res = encodeTypeBaseAsKey(RS_GET_TYPE_BASE(T));
+  // Push PointeeType after the base type
+  mEncodedRSTypeInfo.push_back(PointeeType);
+  return Res;
+}
+
+unsigned RSMetadataEncoderInternal::encodeVectorType(const union RSType *T) {
+  return encodeTypeBaseAsKey(RS_GET_TYPE_BASE(T));
+}
+
+unsigned RSMetadataEncoderInternal::encodeMatrixType(const union RSType *T) {
+  return encodeTypeBaseAsKey(RS_GET_TYPE_BASE(T));
+}
+
+unsigned
+RSMetadataEncoderInternal::encodeConstantArrayType(const union RSType *T) {
+  // Encode element type
+  unsigned ElementType =
+      encodeRSType(RS_CONSTANT_ARRAY_TYPE_GET_ELEMENT_TYPE(T));
+  if (!checkReturnIndex(ElementType))
+    return 0;
+
+  unsigned Res = encodeTypeBase(RS_GET_TYPE_BASE(T));
+  // Push the ElementType after the type base
+  mEncodedRSTypeInfo.push_back(ElementType);
+  return Res;
+}
+
+unsigned RSMetadataEncoderInternal::encodeRecordType(const union RSType *T) {
+  // Construct record name
+  std::string RecordInfoMetadataName(RS_EXPORT_RECORD_TYPE_NAME_MN_PREFIX);
+  RecordInfoMetadataName.append(RS_RECORD_TYPE_GET_NAME(T));
+
+  // Try to find it in mRecordTypes
+  RecordTypesMapTy::const_iterator I =
+      mRecordTypes.find(RecordInfoMetadataName);
+
+  // This record type has been encoded before. Fast return its index here.
+  if (I != mRecordTypes.end())
+    return (I->second + 1);
+
+  // Encode this record type into mTypes. Encode record name string first.
+  unsigned RecordName = joinString(RecordInfoMetadataName);
+  if (!checkReturnIndex(RecordName))
+    return 0;
+
+  unsigned Base = encodeTypeBase(RS_GET_TYPE_BASE(T));
+  if (!checkReturnIndex(Base))
+    return 0;
+
+  // Push record name after encoding the type base
+  mEncodedRSTypeInfo.push_back(RecordName);
+
+  // Add this record type into the map
+  std::pair<StringsMapTy::iterator, bool> Res =
+      mRecordTypes.insert(std::make_pair(RecordInfoMetadataName, Base));
+  // Insertion failed
+  if (!Res.second)
+    return 0;
+
+  // Create a named MDNode for this record type. We cannot create this before
+  // encoding type base into Types and updating mRecordTypes. This is because
+  // we may have structure like:
+  //
+  //            struct foo {
+  //              ...
+  //              struct foo *bar;  // self type reference
+  //              ...
+  //            }
+  llvm::NamedMDNode *RecordInfoMetadata =
+      mModule->getOrInsertNamedMetadata(RecordInfoMetadataName);
+
+  assert((RecordInfoMetadata->getNumOperands() == 0) &&
+         "Record created before!");
+
+  // Encode field info into this named MDNode
+  llvm::SmallVector<llvm::Value*, 3> FieldInfo;
+
+  for (unsigned i = 0; i < RS_RECORD_TYPE_GET_NUM_FIELDS(T); i++) {
+    // 1. field name
+    unsigned FieldName = joinString(RS_RECORD_TYPE_GET_FIELD_NAME(T, i));
+    if (!checkReturnIndex(FieldName))
+      return 0;
+    if (!EncodeInteger(mModule->getContext(),
+                       FieldName,
+                       FieldInfo))
+      return 0;
+
+    // 2. field type
+    unsigned FieldType = encodeRSType(RS_RECORD_TYPE_GET_FIELD_TYPE(T, i));
+    if (!checkReturnIndex(FieldType))
+      return 0;
+    if (!EncodeInteger(mModule->getContext(),
+                       FieldType,
+                       FieldInfo))
+      return 0;
+
+    // 3. field data kind
+    if (!EncodeInteger(mModule->getContext(),
+                       RS_RECORD_TYPE_GET_FIELD_DATA_KIND(T, i),
+                       FieldInfo))
+      return 0;
+
+    RecordInfoMetadata->addOperand(llvm::MDNode::get(mModule->getContext(),
+                                                     FieldInfo.data(),
+                                                     FieldInfo.size()));
+    FieldInfo.clear();
+  }
+
+  return (Res.first->second + 1);
+}
+
+unsigned RSMetadataEncoderInternal::encodeRSType(const union RSType *T) {
+  switch (static_cast<enum RSTypeClass>(RS_TYPE_GET_CLASS(T))) {
+#define ENUM_RS_DATA_TYPE_CLASS(x)  \
+    case RS_TC_ ## x: return encode ## x ## Type(T);
+    RS_DATA_TYPE_CLASS_ENUMS
+#undef ENUM_RS_DATA_TYPE_CLASS
+    default: return 0;
+  }
+  return 0;
+}
+
+int RSMetadataEncoderInternal::encodeRSVar(const RSVar *V) {
+  // check parameter
+  if ((V == NULL) || (V->name == NULL) || (V->type == NULL))
+    return -1;
+
+  // 1. var name
+  unsigned VarName = joinString(V->name);
+  if (!checkReturnIndex(VarName))
+    return -2;
+
+  // 2. type
+  unsigned Type = encodeRSType(V->type);
+
+  llvm::SmallVector<llvm::Value*, 1> VarInfo;
+
+  if (!EncodeInteger(mModule->getContext(), VarName, VarInfo))
+    return -3;
+  if (!EncodeInteger(mModule->getContext(), Type, VarInfo))
+    return -4;
+
+  if (mVarInfoMetadata == NULL)
+    mVarInfoMetadata = mModule->getOrInsertNamedMetadata(RS_EXPORT_VAR_MN);
+
+  mVarInfoMetadata->addOperand(llvm::MDNode::get(mModule->getContext(),
+                                                 VarInfo.data(),
+                                                 VarInfo.size()));
+
+  return 0;
+}
+
+int RSMetadataEncoderInternal::encodeRSFunc(const RSFunction *F) {
+  // check parameter
+  if ((F == NULL) || (F->name == NULL))
+    return -1;
+
+  // 1. var name
+  unsigned FuncName = joinString(F->name);
+  if (!checkReturnIndex(FuncName))
+    return -2;
+
+  llvm::SmallVector<llvm::Value*, 1> FuncInfo;
+  if (!EncodeInteger(mModule->getContext(), FuncName, FuncInfo))
+    return -3;
+
+  if (mFuncInfoMetadata == NULL)
+    mFuncInfoMetadata = mModule->getOrInsertNamedMetadata(RS_EXPORT_FUNC_MN);
+
+  mFuncInfoMetadata->addOperand(llvm::MDNode::get(mModule->getContext(),
+                                                  FuncInfo.data(),
+                                                  FuncInfo.size()));
+
+  return 0;
+}
+
+// Write string table and string index table
+int RSMetadataEncoderInternal::flushStringTable() {
+  assert((mCurStringIndex == mEncodedStrings.size()));
+  assert((mCurStringIndex == mStrings.size()));
+
+  if (mCurStringIndex == 0)
+    return 0;
+
+  // Prepare named MDNode for string table and string index table.
+  llvm::NamedMDNode *RSMetadataStrTab =
+      mModule->getOrInsertNamedMetadata(RS_METADATA_STRTAB_MN);
+  RSMetadataStrTab->dropAllReferences();
+
+  unsigned StrTabSize = 0;
+  unsigned *StrIdx = reinterpret_cast<unsigned*>(
+                        ::malloc((mStrings.size() + 1) * sizeof(unsigned)));
+
+  if (StrIdx == NULL)
+    return -1;
+
+  unsigned StrIdxI = 0;  // iterator for array StrIdx
+
+  // count StrTabSize and fill StrIdx by the way
+  for (std::list<const char*>::const_iterator I = mEncodedStrings.begin(),
+          E = mEncodedStrings.end();
+       I != E;
+       I++) {
+    StrIdx[StrIdxI++] = StrTabSize;
+    StrTabSize += ::strlen(*I) + 1 /* for '\0' */;
+  }
+  StrIdx[StrIdxI] = StrTabSize;
+
+  // Allocate
+  char *StrTab = reinterpret_cast<char*>(::malloc(StrTabSize));
+  if (StrTab == NULL) {
+    free(StrIdx);
+    return -1;
+  }
+
+  llvm::StringRef StrTabData(StrTab, StrTabSize);
+  llvm::StringRef StrIdxData(reinterpret_cast<const char*>(StrIdx),
+                             mStrings.size() * sizeof(unsigned));
+
+  // Copy
+  StrIdxI = 1;
+  for (std::list<const char*>::const_iterator I = mEncodedStrings.begin(),
+          E = mEncodedStrings.end();
+       I != E;
+       I++) {
+    // Get string length from StrIdx (O(1)) instead of call strlen again (O(n)).
+    unsigned CurStrLength = StrIdx[StrIdxI] - StrIdx[StrIdxI - 1];
+    ::memcpy(StrTab, *I, CurStrLength);
+    // Move forward the pointer
+    StrTab += CurStrLength;
+    StrIdxI++;
+  }
+
+  // Flush to metadata
+  llvm::Value *StrTabMDS =
+      llvm::MDString::get(mModule->getContext(), StrTabData);
+  llvm::Value *StrIdxMDS =
+      llvm::MDString::get(mModule->getContext(), StrIdxData);
+
+  if ((StrTabMDS == NULL) || (StrIdxMDS == NULL)) {
+    free(StrIdx);
+    free(StrTab);
+    return -1;
+  }
+
+  llvm::SmallVector<llvm::Value*, 2> StrTabVal;
+  StrTabVal.push_back(StrTabMDS);
+  StrTabVal.push_back(StrIdxMDS);
+  RSMetadataStrTab->addOperand(llvm::MDNode::get(mModule->getContext(),
+                                                 StrTabVal.data(),
+                                                 StrTabVal.size()));
+
+  return 0;
+}
+
+// Write RS type stream
+int RSMetadataEncoderInternal::flushTypeInfo() {
+  unsigned TypeInfoCount = mEncodedRSTypeInfo.size();
+  if (TypeInfoCount <= 0)
+    return 0;
+
+  llvm::NamedMDNode *RSTypeInfo =
+      mModule->getOrInsertNamedMetadata(RS_TYPE_INFO_MN);
+  RSTypeInfo->dropAllReferences();
+
+  unsigned *TypeInfos =
+      reinterpret_cast<unsigned*>(::malloc(TypeInfoCount * sizeof(unsigned)));
+  unsigned TypeInfosIdx = 0;  // iterator for array TypeInfos
+
+  if (TypeInfos == NULL)
+    return -1;
+
+  for (std::list<unsigned>::const_iterator I = mEncodedRSTypeInfo.begin(),
+          E = mEncodedRSTypeInfo.end();
+       I != E;
+       I++)
+    TypeInfos[TypeInfosIdx++] = *I;
+
+  llvm::StringRef TypeInfoData(reinterpret_cast<const char*>(TypeInfos),
+                               TypeInfoCount * sizeof(unsigned));
+  llvm::Value *TypeInfoMDS =
+      llvm::MDString::get(mModule->getContext(), TypeInfoData);
+  if (TypeInfoMDS == NULL) {
+    free(TypeInfos);
+    return -1;
+  }
+
+  RSTypeInfo->addOperand(llvm::MDNode::get(mModule->getContext(),
+                                           &TypeInfoMDS, 1));
+  free(TypeInfos);
+
+  return 0;
+}
+
+int RSMetadataEncoderInternal::finalize() {
+  int Res = flushStringTable();
+  if (Res != 0)
+    return Res;
+
+  Res = flushTypeInfo();
+  if (Res != 0)
+    return Res;
+
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// APIs
+///////////////////////////////////////////////////////////////////////////////
+RSMetadataEncoder *CreateRSMetadataEncoder(llvm::Module *M) {
+  return reinterpret_cast<RSMetadataEncoder*>(new RSMetadataEncoderInternal(M));
+}
+
+int RSEncodeVarMetadata(RSMetadataEncoder *E, const RSVar *V) {
+  return reinterpret_cast<RSMetadataEncoderInternal*>(E)->encodeRSVar(V);
+}
+
+int RSEncodeFunctionMetadata(RSMetadataEncoder *E, const RSFunction *F) {
+  return reinterpret_cast<RSMetadataEncoderInternal*>(E)->encodeRSFunc(F);
+}
+
+void DestroyRSMetadataEncoder(RSMetadataEncoder *E) {
+  RSMetadataEncoderInternal *C =
+      reinterpret_cast<RSMetadataEncoderInternal*>(E);
+  delete C;
+  return;
+}
+
+int FinalizeRSMetadataEncoder(RSMetadataEncoder *E) {
+  RSMetadataEncoderInternal *C =
+      reinterpret_cast<RSMetadataEncoderInternal*>(E);
+  int Res = C->finalize();
+  DestroyRSMetadataEncoder(E);
+  return Res;
+}