| /* |
| * 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 <cstdlib> |
| #include <list> |
| #include <map> |
| #include <string> |
| |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/StringRef.h" |
| |
| #include "llvm/Metadata.h" |
| #include "llvm/Module.h" |
| |
| #include "slang_assert.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: |
| explicit 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); |
| |
| slangAssert((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; |
| } |
| |
| llvm::ArrayRef<llvm::Value*> FieldInfoArray(FieldInfo); |
| RecordInfoMetadata->addOperand(llvm::MDNode::get(mModule->getContext(), |
| FieldInfoArray)); |
| 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); |
| |
| llvm::ArrayRef<llvm::Value*> VarInfoArray(VarInfo); |
| mVarInfoMetadata->addOperand(llvm::MDNode::get(mModule->getContext(), |
| VarInfoArray)); |
| |
| 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); |
| |
| llvm::ArrayRef<llvm::Value*> FuncInfoArray(FuncInfo); |
| mFuncInfoMetadata->addOperand(llvm::MDNode::get(mModule->getContext(), |
| FuncInfoArray)); |
| |
| return 0; |
| } |
| |
| // Write string table and string index table |
| int RSMetadataEncoderInternal::flushStringTable() { |
| slangAssert((mCurStringIndex == mEncodedStrings.size())); |
| slangAssert((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); |
| llvm::ArrayRef<llvm::Value*> StrTabValArray(StrTabVal); |
| RSMetadataStrTab->addOperand(llvm::MDNode::get(mModule->getContext(), |
| StrTabValArray)); |
| |
| 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; |
| } |
| |
| llvm::SmallVector<llvm::Value*, 1> TypeInfo; |
| TypeInfo.push_back(TypeInfoMDS); |
| |
| llvm::ArrayRef<llvm::Value*> TypeInfoArray(TypeInfo); |
| |
| RSTypeInfo->addOperand(llvm::MDNode::get(mModule->getContext(), |
| TypeInfoArray)); |
| 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; |
| } |