/* * Copyright 2011-2012, 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 "bcinfo/MetadataExtractor.h" #include "bcinfo/BitcodeWrapper.h" #define LOG_TAG "bcinfo" #include <cutils/log.h> #include <cutils/properties.h> #include "llvm/ADT/OwningPtr.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Constants.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/Support/MemoryBuffer.h" #include <cstdlib> namespace bcinfo { // Name of metadata node where pragma info resides (should be synced with // slang.cpp) static const llvm::StringRef PragmaMetadataName = "#pragma"; // Name of metadata node where exported variable names reside (should be // synced with slang_rs_metadata.h) static const llvm::StringRef ExportVarMetadataName = "#rs_export_var"; // Name of metadata node where exported function names reside (should be // synced with slang_rs_metadata.h) static const llvm::StringRef ExportFuncMetadataName = "#rs_export_func"; // Name of metadata node where exported ForEach name information resides // (should be synced with slang_rs_metadata.h) static const llvm::StringRef ExportForEachNameMetadataName = "#rs_export_foreach_name"; // Name of metadata node where exported ForEach signature information resides // (should be synced with slang_rs_metadata.h) static const llvm::StringRef ExportForEachMetadataName = "#rs_export_foreach"; // Name of metadata node where RS object slot info resides (should be // synced with slang_rs_metadata.h) static const llvm::StringRef ObjectSlotMetadataName = "#rs_object_slots"; MetadataExtractor::MetadataExtractor(const char *bitcode, size_t bitcodeSize) : mModule(NULL), mBitcode(bitcode), mBitcodeSize(bitcodeSize), mExportVarCount(0), mExportFuncCount(0), mExportForEachSignatureCount(0), mExportVarNameList(NULL), mExportFuncNameList(NULL), mExportForEachNameList(NULL), mExportForEachSignatureList(NULL), mPragmaCount(0), mPragmaKeyList(NULL), mPragmaValueList(NULL), mObjectSlotCount(0), mObjectSlotList(NULL), mRSFloatPrecision(RS_FP_Full) { BitcodeWrapper wrapper(bitcode, bitcodeSize); mCompilerVersion = wrapper.getCompilerVersion(); mOptimizationLevel = wrapper.getOptimizationLevel(); } MetadataExtractor::MetadataExtractor(const llvm::Module *module) : mModule(module), mBitcode(NULL), mBitcodeSize(0), mExportVarCount(0), mExportFuncCount(0), mExportForEachSignatureCount(0), mExportVarNameList(NULL), mExportFuncNameList(NULL), mExportForEachNameList(NULL), mExportForEachSignatureList(NULL), mPragmaCount(0), mPragmaKeyList(NULL), mPragmaValueList(NULL), mObjectSlotCount(0), mObjectSlotList(NULL), mRSFloatPrecision(RS_FP_Full) { mCompilerVersion = 0; mOptimizationLevel = 3; } MetadataExtractor::~MetadataExtractor() { if (mExportVarNameList) { for (size_t i = 0; i < mExportVarCount; i++) { delete [] mExportVarNameList[i]; mExportVarNameList[i] = NULL; } } delete [] mExportVarNameList; mExportVarNameList = NULL; if (mExportFuncNameList) { for (size_t i = 0; i < mExportFuncCount; i++) { delete [] mExportFuncNameList[i]; mExportFuncNameList[i] = NULL; } } delete [] mExportFuncNameList; mExportFuncNameList = NULL; if (mExportForEachNameList) { for (size_t i = 0; i < mExportForEachSignatureCount; i++) { delete [] mExportForEachNameList[i]; mExportForEachNameList[i] = NULL; } } delete [] mExportForEachNameList; mExportForEachNameList = NULL; delete [] mExportForEachSignatureList; mExportForEachSignatureList = NULL; for (size_t i = 0; i < mPragmaCount; i++) { if (mPragmaKeyList) { delete [] mPragmaKeyList[i]; mPragmaKeyList[i] = NULL; } if (mPragmaValueList) { delete [] mPragmaValueList[i]; mPragmaValueList[i] = NULL; } } delete [] mPragmaKeyList; mPragmaKeyList = NULL; delete [] mPragmaValueList; mPragmaValueList = NULL; delete [] mObjectSlotList; mObjectSlotList = NULL; return; } bool MetadataExtractor::populateObjectSlotMetadata( const llvm::NamedMDNode *ObjectSlotMetadata) { if (!ObjectSlotMetadata) { return true; } mObjectSlotCount = ObjectSlotMetadata->getNumOperands(); if (!mObjectSlotCount) { return true; } uint32_t *TmpSlotList = new uint32_t[mObjectSlotCount]; memset(TmpSlotList, 0, mObjectSlotCount * sizeof(*TmpSlotList)); for (size_t i = 0; i < mObjectSlotCount; i++) { llvm::MDNode *ObjectSlot = ObjectSlotMetadata->getOperand(i); if (ObjectSlot != NULL && ObjectSlot->getNumOperands() == 1) { llvm::Value *SlotMDS = ObjectSlot->getOperand(0); if (SlotMDS->getValueID() == llvm::Value::MDStringVal) { llvm::StringRef Slot = static_cast<llvm::MDString*>(SlotMDS)->getString(); uint32_t USlot = 0; if (Slot.getAsInteger(10, USlot)) { ALOGE("Non-integer object slot value '%s'", Slot.str().c_str()); return false; } TmpSlotList[i] = USlot; } } } mObjectSlotList = TmpSlotList; return true; } static const char *createStringFromValue(llvm::Value *v) { if (v->getValueID() != llvm::Value::MDStringVal) { return NULL; } llvm::StringRef ref = static_cast<llvm::MDString*>(v)->getString(); char *c = new char[ref.size() + 1]; memcpy(c, ref.data(), ref.size()); c[ref.size()] = '\0'; return c; } void MetadataExtractor::populatePragmaMetadata( const llvm::NamedMDNode *PragmaMetadata) { if (!PragmaMetadata) { return; } mPragmaCount = PragmaMetadata->getNumOperands(); if (!mPragmaCount) { return; } const char **TmpKeyList = new const char*[mPragmaCount]; const char **TmpValueList = new const char*[mPragmaCount]; for (size_t i = 0; i < mPragmaCount; i++) { llvm::MDNode *Pragma = PragmaMetadata->getOperand(i); if (Pragma != NULL && Pragma->getNumOperands() == 2) { llvm::Value *PragmaKeyMDS = Pragma->getOperand(0); TmpKeyList[i] = createStringFromValue(PragmaKeyMDS); llvm::Value *PragmaValueMDS = Pragma->getOperand(1); TmpValueList[i] = createStringFromValue(PragmaValueMDS); } } mPragmaKeyList = TmpKeyList; mPragmaValueList = TmpValueList; // Check to see if we have any FP precision-related pragmas. std::string Relaxed("rs_fp_relaxed"); std::string Imprecise("rs_fp_imprecise"); std::string Full("rs_fp_full"); bool RelaxedPragmaSeen = false; bool ImprecisePragmaSeen = false; for (size_t i = 0; i < mPragmaCount; i++) { if (!Relaxed.compare(mPragmaKeyList[i])) { if (RelaxedPragmaSeen || ImprecisePragmaSeen) { ALOGE("Multiple float precision pragmas specified!"); } RelaxedPragmaSeen = true; } else if (!Imprecise.compare(mPragmaKeyList[i])) { if (RelaxedPragmaSeen || ImprecisePragmaSeen) { ALOGE("Multiple float precision pragmas specified!"); } ImprecisePragmaSeen = true; } } // Imprecise is selected over Relaxed precision. // In the absence of both, we stick to the default Full precision. if (ImprecisePragmaSeen) { mRSFloatPrecision = RS_FP_Imprecise; } else if (RelaxedPragmaSeen) { mRSFloatPrecision = RS_FP_Relaxed; } // Provide an override for precsion via adb shell setprop // adb shell setprop debug.rs.precision rs_fp_full // adb shell setprop debug.rs.precision rs_fp_relaxed // adb shell setprop debug.rs.precision rs_fp_imprecise char PrecisionPropBuf[PROPERTY_VALUE_MAX]; const std::string PrecisionPropName("debug.rs.precision"); property_get("debug.rs.precision", PrecisionPropBuf, ""); if (PrecisionPropBuf[0]) { if (!Relaxed.compare(PrecisionPropBuf)) { ALOGE("Switching to RS FP relaxed mode via setprop"); mRSFloatPrecision = RS_FP_Relaxed; } else if (!Imprecise.compare(PrecisionPropBuf)) { ALOGE("Switching to RS FP imprecise mode via setprop"); mRSFloatPrecision = RS_FP_Imprecise; } else if (!Full.compare(PrecisionPropBuf)) { ALOGE("Switching to RS FP full mode via setprop"); mRSFloatPrecision = RS_FP_Full; } } return; } bool MetadataExtractor::populateVarNameMetadata( const llvm::NamedMDNode *VarNameMetadata) { if (!VarNameMetadata) { return true; } mExportVarCount = VarNameMetadata->getNumOperands(); if (!mExportVarCount) { return true; } const char **TmpNameList = new const char *[mExportVarCount]; for (size_t i = 0; i < mExportVarCount; i++) { llvm::MDNode *Name = VarNameMetadata->getOperand(i); if (Name != NULL && Name->getNumOperands() > 1) { TmpNameList[i] = createStringFromValue(Name->getOperand(0)); } } mExportVarNameList = TmpNameList; return true; } bool MetadataExtractor::populateFuncNameMetadata( const llvm::NamedMDNode *FuncNameMetadata) { if (!FuncNameMetadata) { return true; } mExportFuncCount = FuncNameMetadata->getNumOperands(); if (!mExportFuncCount) { return true; } const char **TmpNameList = new const char*[mExportFuncCount]; for (size_t i = 0; i < mExportFuncCount; i++) { llvm::MDNode *Name = FuncNameMetadata->getOperand(i); if (Name != NULL && Name->getNumOperands() == 1) { TmpNameList[i] = createStringFromValue(Name->getOperand(0)); } } mExportFuncNameList = TmpNameList; return true; } bool MetadataExtractor::populateForEachMetadata( const llvm::NamedMDNode *Names, const llvm::NamedMDNode *Signatures) { if (!Names && !Signatures) { // Handle legacy case for pre-ICS bitcode that doesn't contain a metadata // section for ForEach. We generate a full signature for a "root" function // which means that we need to set the bottom 5 bits in the mask. mExportForEachSignatureCount = 1; char **TmpNameList = new char*[mExportForEachSignatureCount]; TmpNameList[0] = new char[5]; strncpy(TmpNameList[0], "root", 5); uint32_t *TmpSigList = new uint32_t[mExportForEachSignatureCount]; TmpSigList[0] = 0x1f; mExportForEachNameList = (const char**)TmpNameList; mExportForEachSignatureList = TmpSigList; return true; } if (Signatures) { mExportForEachSignatureCount = Signatures->getNumOperands(); if (!mExportForEachSignatureCount) { return true; } } else { mExportForEachSignatureCount = 0; mExportForEachSignatureList = NULL; return true; } uint32_t *TmpSigList = new uint32_t[mExportForEachSignatureCount]; const char **TmpNameList = new const char*[mExportForEachSignatureCount]; for (size_t i = 0; i < mExportForEachSignatureCount; i++) { llvm::MDNode *SigNode = Signatures->getOperand(i); if (SigNode != NULL && SigNode->getNumOperands() == 1) { llvm::Value *SigVal = SigNode->getOperand(0); if (SigVal->getValueID() == llvm::Value::MDStringVal) { llvm::StringRef SigString = static_cast<llvm::MDString*>(SigVal)->getString(); uint32_t Signature = 0; if (SigString.getAsInteger(10, Signature)) { ALOGE("Non-integer signature value '%s'", SigString.str().c_str()); return false; } TmpSigList[i] = Signature; } } } if (Names) { for (size_t i = 0; i < mExportForEachSignatureCount; i++) { llvm::MDNode *Name = Names->getOperand(i); if (Name != NULL && Name->getNumOperands() == 1) { TmpNameList[i] = createStringFromValue(Name->getOperand(0)); } } } else { if (mExportForEachSignatureCount != 1) { ALOGE("mExportForEachSignatureCount = %zu, but should be 1", mExportForEachSignatureCount); } char *RootName = new char[5]; strncpy(RootName, "root", 5); TmpNameList[0] = RootName; } mExportForEachNameList = TmpNameList; mExportForEachSignatureList = TmpSigList; return true; } bool MetadataExtractor::extract() { if (!(mBitcode && mBitcodeSize) && !mModule) { ALOGE("Invalid/empty bitcode/module"); return false; } llvm::OwningPtr<llvm::LLVMContext> mContext; if (!mModule) { mContext.reset(new llvm::LLVMContext()); llvm::OwningPtr<llvm::MemoryBuffer> MEM( llvm::MemoryBuffer::getMemBuffer( llvm::StringRef(mBitcode, mBitcodeSize), "", false)); std::string error; // Module ownership is handled by the context, so we don't need to free it. mModule = llvm::ParseBitcodeFile(MEM.get(), *mContext, &error); if (!mModule) { ALOGE("Could not parse bitcode file"); ALOGE("%s", error.c_str()); return false; } } const llvm::NamedMDNode *ExportVarMetadata = mModule->getNamedMetadata(ExportVarMetadataName); const llvm::NamedMDNode *ExportFuncMetadata = mModule->getNamedMetadata(ExportFuncMetadataName); const llvm::NamedMDNode *ExportForEachNameMetadata = mModule->getNamedMetadata(ExportForEachNameMetadataName); const llvm::NamedMDNode *ExportForEachMetadata = mModule->getNamedMetadata(ExportForEachMetadataName); const llvm::NamedMDNode *PragmaMetadata = mModule->getNamedMetadata(PragmaMetadataName); const llvm::NamedMDNode *ObjectSlotMetadata = mModule->getNamedMetadata(ObjectSlotMetadataName); if (!populateVarNameMetadata(ExportVarMetadata)) { ALOGE("Could not populate export variable metadata"); return false; } if (!populateFuncNameMetadata(ExportFuncMetadata)) { ALOGE("Could not populate export function metadata"); return false; } if (!populateForEachMetadata(ExportForEachNameMetadata, ExportForEachMetadata)) { ALOGE("Could not populate ForEach signature metadata"); return false; } populatePragmaMetadata(PragmaMetadata); if (!populateObjectSlotMetadata(ObjectSlotMetadata)) { ALOGE("Could not populate object slot metadata"); return false; } return true; } } // namespace bcinfo